@copilotz/admin 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,15 +1,17 @@
1
1
  // src/CopilotzAdmin.tsx
2
2
  import {
3
+ useCallback as useCallback8,
3
4
  useDeferredValue,
4
- useMemo as useMemo2,
5
- useState as useState2
5
+ useEffect as useEffect9,
6
+ useMemo as useMemo3,
7
+ useState as useState9
6
8
  } from "react";
7
9
 
8
10
  // src/config.ts
9
11
  var defaultAdminConfig = {
10
12
  branding: {
11
13
  title: "Copilotz Admin",
12
- subtitle: "Read-only operational visibility for Copilotz clients",
14
+ subtitle: "Operational visibility for Copilotz clients",
13
15
  logo: null,
14
16
  actions: null
15
17
  },
@@ -43,24 +45,36 @@ var defaultAdminConfig = {
43
45
  scopeScoped: "Scoped",
44
46
  configured: "Configured",
45
47
  unconfigured: "Observed only",
46
- noResults: "No results"
48
+ noResults: "No results",
49
+ eventsTitle: "Events",
50
+ dashboardTitle: "Dashboard",
51
+ collectionsTitle: "Collections",
52
+ collectionsEndpoint: "/v1/collections"
47
53
  },
48
54
  features: {
49
55
  showOverview: true,
50
56
  showActivity: true,
51
57
  showThreads: true,
52
58
  showParticipants: true,
53
- showAgents: true
59
+ showAgents: true,
60
+ showEvents: true,
61
+ showCollections: true
54
62
  },
55
63
  ui: {
56
64
  compact: false,
57
65
  maxActivityBars: 18
58
66
  },
67
+ sidebar: {
68
+ defaultOpen: true,
69
+ collapsible: "icon"
70
+ },
59
71
  baseUrl: "",
60
72
  getRequestHeaders: async () => ({}),
61
73
  namespace: "",
62
74
  initialRange: "7d",
63
- initialInterval: "day"
75
+ initialInterval: "day",
76
+ defaultPage: "dashboard",
77
+ onNavigate: null
64
78
  };
65
79
  function mergeAdminConfig(_baseConfig, userConfig) {
66
80
  if (!userConfig) return defaultAdminConfig;
@@ -81,11 +95,17 @@ function mergeAdminConfig(_baseConfig, userConfig) {
81
95
  ...defaultAdminConfig.ui,
82
96
  ...userConfig.ui
83
97
  },
98
+ sidebar: {
99
+ ...defaultAdminConfig.sidebar,
100
+ ...userConfig.sidebar
101
+ },
84
102
  baseUrl: userConfig.baseUrl ?? defaultAdminConfig.baseUrl,
85
103
  getRequestHeaders: userConfig.getRequestHeaders ?? defaultAdminConfig.getRequestHeaders,
86
104
  namespace: userConfig.namespace ?? defaultAdminConfig.namespace,
87
105
  initialRange: userConfig.initialRange ?? defaultAdminConfig.initialRange,
88
- initialInterval: userConfig.initialInterval ?? defaultAdminConfig.initialInterval
106
+ initialInterval: userConfig.initialInterval ?? defaultAdminConfig.initialInterval,
107
+ defaultPage: userConfig.defaultPage ?? defaultAdminConfig.defaultPage,
108
+ onNavigate: userConfig.onNavigate ?? defaultAdminConfig.onNavigate
89
109
  };
90
110
  }
91
111
 
@@ -159,6 +179,21 @@ async function fetchAdminJson(path, params, options) {
159
179
  const payload = await response.json();
160
180
  return payload.data;
161
181
  }
182
+ async function fetchRawJson(path, params, options) {
183
+ const url = new URL(`${resolveBaseUrl(options?.baseUrl)}${path}`, window.location.origin);
184
+ for (const [key, value] of Object.entries(params)) {
185
+ if (typeof value === "string" && value.length > 0) {
186
+ url.searchParams.set(key, value);
187
+ }
188
+ }
189
+ const response = await fetch(url.toString(), {
190
+ headers: await withAuthHeaders({}, options?.getRequestHeaders)
191
+ });
192
+ if (!response.ok) {
193
+ throw new Error(`Admin request failed (${response.status})`);
194
+ }
195
+ return await response.json();
196
+ }
162
197
  async function fetchAdminOverview(range, namespace, options) {
163
198
  const windowRange = getRangeWindow(range);
164
199
  return await fetchAdminJson("/v1/admin/overview", {
@@ -197,6 +232,139 @@ async function fetchAdminAgents(search, namespace, options) {
197
232
  limit: "8"
198
233
  }, options);
199
234
  }
235
+ async function fetchThreadDetail(threadId, options) {
236
+ return await fetchAdminJson(
237
+ `/v1/threads/${encodeURIComponent(threadId)}`,
238
+ {},
239
+ options
240
+ );
241
+ }
242
+ async function fetchThreadMessages(threadId, messageOptions, options) {
243
+ return await fetchRawJson(
244
+ `/v1/threads/${encodeURIComponent(threadId)}/messages`,
245
+ {
246
+ limit: messageOptions?.limit?.toString(),
247
+ before: messageOptions?.before
248
+ },
249
+ options
250
+ );
251
+ }
252
+ async function fetchParticipantDetail(participantId, options) {
253
+ return await fetchAdminJson(
254
+ `/v1/participants/${encodeURIComponent(participantId)}`,
255
+ {},
256
+ options
257
+ );
258
+ }
259
+ async function updateParticipant(participantId, data, options) {
260
+ const url = new URL(
261
+ `${resolveBaseUrl(options?.baseUrl)}/v1/participants/${encodeURIComponent(participantId)}`,
262
+ window.location.origin
263
+ );
264
+ const response = await fetch(url.toString(), {
265
+ method: "PUT",
266
+ headers: await withAuthHeaders(
267
+ { "Content-Type": "application/json" },
268
+ options?.getRequestHeaders
269
+ ),
270
+ body: JSON.stringify(data)
271
+ });
272
+ if (!response.ok) {
273
+ throw new Error(`Update participant failed (${response.status})`);
274
+ }
275
+ const payload = await response.json();
276
+ return payload.data;
277
+ }
278
+ async function fetchCollectionNames(options) {
279
+ return await fetchAdminJson("/v1/collections", {}, options);
280
+ }
281
+ async function fetchCollectionItems(collection, queryOptions, options) {
282
+ const params = {
283
+ namespace: queryOptions?.namespace,
284
+ limit: queryOptions?.limit?.toString()
285
+ };
286
+ if (queryOptions?.search) {
287
+ params.q = queryOptions.search;
288
+ } else {
289
+ params.offset = queryOptions?.offset?.toString();
290
+ }
291
+ return await fetchAdminJson(
292
+ `/v1/collections/${encodeURIComponent(collection)}`,
293
+ params,
294
+ options
295
+ );
296
+ }
297
+ async function fetchCollectionItem(collection, itemId, namespace, options) {
298
+ return await fetchAdminJson(
299
+ `/v1/collections/${encodeURIComponent(collection)}/${encodeURIComponent(itemId)}`,
300
+ { namespace },
301
+ options
302
+ );
303
+ }
304
+ async function createCollectionItem(collection, data, namespace, options) {
305
+ const url = new URL(
306
+ `${resolveBaseUrl(options?.baseUrl)}/v1/collections/${encodeURIComponent(collection)}`,
307
+ window.location.origin
308
+ );
309
+ if (namespace) url.searchParams.set("namespace", namespace);
310
+ const response = await fetch(url.toString(), {
311
+ method: "POST",
312
+ headers: await withAuthHeaders(
313
+ { "Content-Type": "application/json" },
314
+ options?.getRequestHeaders
315
+ ),
316
+ body: JSON.stringify(data)
317
+ });
318
+ if (!response.ok) {
319
+ throw new Error(`Create collection item failed (${response.status})`);
320
+ }
321
+ const payload = await response.json();
322
+ if ("body" in payload && payload.body && typeof payload.body === "object") {
323
+ return payload.body;
324
+ }
325
+ return payload;
326
+ }
327
+ async function updateCollectionItem(collection, itemId, data, namespace, options) {
328
+ const url = new URL(
329
+ `${resolveBaseUrl(options?.baseUrl)}/v1/collections/${encodeURIComponent(collection)}/${encodeURIComponent(itemId)}`,
330
+ window.location.origin
331
+ );
332
+ if (namespace) url.searchParams.set("namespace", namespace);
333
+ const response = await fetch(url.toString(), {
334
+ method: "PUT",
335
+ headers: await withAuthHeaders(
336
+ { "Content-Type": "application/json" },
337
+ options?.getRequestHeaders
338
+ ),
339
+ body: JSON.stringify(data)
340
+ });
341
+ if (!response.ok) {
342
+ throw new Error(`Update collection item failed (${response.status})`);
343
+ }
344
+ const payload = await response.json();
345
+ return payload.data;
346
+ }
347
+ async function deleteCollectionItem(collection, itemId, namespace, options) {
348
+ const url = new URL(
349
+ `${resolveBaseUrl(options?.baseUrl)}/v1/collections/${encodeURIComponent(collection)}/${encodeURIComponent(itemId)}`,
350
+ window.location.origin
351
+ );
352
+ if (namespace) url.searchParams.set("namespace", namespace);
353
+ const response = await fetch(url.toString(), {
354
+ method: "DELETE",
355
+ headers: await withAuthHeaders({}, options?.getRequestHeaders)
356
+ });
357
+ if (!response.ok) {
358
+ throw new Error(`Delete collection item failed (${response.status})`);
359
+ }
360
+ }
361
+ async function fetchThreadEvents(threadId, options) {
362
+ return await fetchAdminJson(
363
+ `/v1/threads/${encodeURIComponent(threadId)}/events`,
364
+ {},
365
+ options
366
+ );
367
+ }
200
368
 
201
369
  // src/useCopilotzAdmin.ts
202
370
  function useCopilotzAdmin(options = {}) {
@@ -322,6 +490,19 @@ function Card({ className, ...props }) {
322
490
  }
323
491
  );
324
492
  }
493
+ function CardHeader({ className, ...props }) {
494
+ return /* @__PURE__ */ jsx(
495
+ "div",
496
+ {
497
+ "data-slot": "card-header",
498
+ className: cn(
499
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
500
+ className
501
+ ),
502
+ ...props
503
+ }
504
+ );
505
+ }
325
506
  function CardContent({ className, ...props }) {
326
507
  return /* @__PURE__ */ jsx(
327
508
  "div",
@@ -380,10 +561,83 @@ function Button({
380
561
  );
381
562
  }
382
563
 
564
+ // src/components/ui/tooltip.tsx
565
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
566
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
567
+ function TooltipProvider({
568
+ delayDuration = 0,
569
+ ...props
570
+ }) {
571
+ return /* @__PURE__ */ jsx3(
572
+ TooltipPrimitive.Provider,
573
+ {
574
+ "data-slot": "tooltip-provider",
575
+ delayDuration,
576
+ ...props
577
+ }
578
+ );
579
+ }
580
+ function Tooltip({
581
+ ...props
582
+ }) {
583
+ return /* @__PURE__ */ jsx3(TooltipProvider, { children: /* @__PURE__ */ jsx3(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
584
+ }
585
+ function TooltipTrigger({
586
+ ...props
587
+ }) {
588
+ return /* @__PURE__ */ jsx3(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
589
+ }
590
+ function TooltipContent({
591
+ className,
592
+ sideOffset = 0,
593
+ children,
594
+ ...props
595
+ }) {
596
+ return /* @__PURE__ */ jsx3(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
597
+ TooltipPrimitive.Content,
598
+ {
599
+ "data-slot": "tooltip-content",
600
+ sideOffset,
601
+ className: cn(
602
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
603
+ className
604
+ ),
605
+ ...props,
606
+ children: [
607
+ children,
608
+ /* @__PURE__ */ jsx3(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
609
+ ]
610
+ }
611
+ ) });
612
+ }
613
+
614
+ // src/components/ui/sidebar.tsx
615
+ import * as React3 from "react";
616
+ import { Slot as Slot2 } from "@radix-ui/react-slot";
617
+ import { cva as cva2 } from "class-variance-authority";
618
+ import { PanelLeftIcon } from "lucide-react";
619
+
620
+ // src/hooks/use-mobile.ts
621
+ import * as React from "react";
622
+ var MOBILE_BREAKPOINT = 768;
623
+ function useIsMobile() {
624
+ const [isMobile, setIsMobile] = React.useState(void 0);
625
+ React.useEffect(() => {
626
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
627
+ const onChange = () => {
628
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
629
+ };
630
+ mql.addEventListener("change", onChange);
631
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
632
+ return () => mql.removeEventListener("change", onChange);
633
+ }, []);
634
+ return !!isMobile;
635
+ }
636
+
383
637
  // src/components/ui/input.tsx
384
- import { jsx as jsx3 } from "react/jsx-runtime";
638
+ import { jsx as jsx4 } from "react/jsx-runtime";
385
639
  function Input({ className, type, ...props }) {
386
- return /* @__PURE__ */ jsx3(
640
+ return /* @__PURE__ */ jsx4(
387
641
  "input",
388
642
  {
389
643
  type,
@@ -399,326 +653,1009 @@ function Input({ className, type, ...props }) {
399
653
  );
400
654
  }
401
655
 
402
- // src/components/ui/badge.tsx
403
- import { Slot as Slot2 } from "@radix-ui/react-slot";
404
- import { cva as cva2 } from "class-variance-authority";
405
- import { jsx as jsx4 } from "react/jsx-runtime";
406
- var badgeVariants = cva2(
407
- "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
408
- {
409
- variants: {
410
- variant: {
411
- default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
412
- secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
413
- destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
414
- outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
415
- }
416
- },
417
- defaultVariants: {
418
- variant: "default"
419
- }
420
- }
421
- );
422
- function Badge({
656
+ // src/components/ui/separator.tsx
657
+ import * as SeparatorPrimitive from "@radix-ui/react-separator";
658
+ import { jsx as jsx5 } from "react/jsx-runtime";
659
+ function Separator({
423
660
  className,
424
- variant,
425
- asChild = false,
661
+ orientation = "horizontal",
662
+ decorative = true,
426
663
  ...props
427
664
  }) {
428
- const Comp = asChild ? Slot2 : "span";
429
- return /* @__PURE__ */ jsx4(
430
- Comp,
665
+ return /* @__PURE__ */ jsx5(
666
+ SeparatorPrimitive.Root,
431
667
  {
432
- "data-slot": "badge",
433
- className: cn(badgeVariants({ variant }), className),
668
+ "data-slot": "separator",
669
+ decorative,
670
+ orientation,
671
+ className: cn(
672
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
673
+ className
674
+ ),
434
675
  ...props
435
676
  }
436
677
  );
437
678
  }
438
679
 
439
- // src/components/ui/select.tsx
440
- import * as React from "react";
441
- import * as SelectPrimitive from "@radix-ui/react-select";
442
- import { Check, ChevronDown, ChevronUp } from "lucide-react";
443
- import { jsx as jsx5, jsxs } from "react/jsx-runtime";
444
- var Select = SelectPrimitive.Root;
445
- var SelectValue = SelectPrimitive.Value;
446
- var SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
447
- SelectPrimitive.Trigger,
448
- {
449
- ref,
450
- className: cn(
451
- "flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none transition-colors placeholder:text-muted-foreground focus:ring-2 focus:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50",
452
- className
453
- ),
454
- ...props,
455
- children: [
456
- children,
457
- /* @__PURE__ */ jsx5(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx5(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
458
- ]
680
+ // src/components/ui/sheet.tsx
681
+ import * as React2 from "react";
682
+ import * as SheetPrimitive from "@radix-ui/react-dialog";
683
+ import { XIcon } from "lucide-react";
684
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
685
+ function cleanupBodyStyles() {
686
+ if (typeof document !== "undefined" && document.body.style.pointerEvents === "none") {
687
+ document.body.style.pointerEvents = "";
459
688
  }
460
- ));
461
- SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
462
- var SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx5(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
463
- SelectPrimitive.Content,
464
- {
465
- ref,
466
- className: cn(
467
- "relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md",
468
- position === "popper" && "translate-y-1",
469
- className
470
- ),
471
- position,
472
- ...props,
473
- children: [
474
- /* @__PURE__ */ jsx5(SelectPrimitive.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsx5(ChevronUp, { className: "h-4 w-4" }) }),
475
- /* @__PURE__ */ jsx5(
476
- SelectPrimitive.Viewport,
477
- {
478
- className: cn(
479
- "p-1",
480
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
481
- ),
482
- children
483
- }
689
+ }
690
+ function Sheet({ open, onOpenChange, ...props }) {
691
+ const prevOpenRef = React2.useRef(open);
692
+ React2.useEffect(() => {
693
+ if (prevOpenRef.current === true && open === false) {
694
+ const timeout = setTimeout(cleanupBodyStyles, 350);
695
+ return () => clearTimeout(timeout);
696
+ }
697
+ prevOpenRef.current = open;
698
+ }, [open]);
699
+ React2.useEffect(() => {
700
+ return () => {
701
+ cleanupBodyStyles();
702
+ };
703
+ }, []);
704
+ return /* @__PURE__ */ jsx6(SheetPrimitive.Root, { "data-slot": "sheet", open, onOpenChange, ...props });
705
+ }
706
+ function SheetPortal({
707
+ ...props
708
+ }) {
709
+ return /* @__PURE__ */ jsx6(SheetPrimitive.Portal, { "data-slot": "sheet-portal", ...props });
710
+ }
711
+ function SheetOverlay({
712
+ className,
713
+ ...props
714
+ }) {
715
+ return /* @__PURE__ */ jsx6(
716
+ SheetPrimitive.Overlay,
717
+ {
718
+ "data-slot": "sheet-overlay",
719
+ className: cn(
720
+ "fixed inset-0 z-50 bg-black/50",
721
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
722
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
723
+ "data-[state=closed]:pointer-events-none",
724
+ className
484
725
  ),
485
- /* @__PURE__ */ jsx5(SelectPrimitive.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsx5(ChevronDown, { className: "h-4 w-4" }) })
486
- ]
487
- }
488
- ) }));
489
- SelectContent.displayName = SelectPrimitive.Content.displayName;
490
- var SelectItem = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
491
- SelectPrimitive.Item,
492
- {
493
- ref,
494
- className: cn(
495
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
496
- className
497
- ),
498
- ...props,
499
- children: [
500
- /* @__PURE__ */ jsx5(SelectPrimitive.ItemText, { children }),
501
- /* @__PURE__ */ jsx5(SelectPrimitive.ItemIndicator, { className: "absolute right-2 inline-flex items-center justify-center", children: /* @__PURE__ */ jsx5(Check, { className: "h-4 w-4" }) })
502
- ]
503
- }
504
- ));
505
- SelectItem.displayName = SelectPrimitive.Item.displayName;
506
-
507
- // src/CopilotzAdmin.tsx
508
- import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
509
- var CopilotzAdmin = ({
510
- config: userConfig,
511
- className
512
- }) => {
513
- const config = useMemo2(
514
- () => mergeAdminConfig(defaultAdminConfig, userConfig),
515
- [userConfig]
726
+ ...props
727
+ }
516
728
  );
517
- const [threadSearch, setThreadSearch] = useState2("");
518
- const [participantSearch, setParticipantSearch] = useState2("");
519
- const [agentSearch, setAgentSearch] = useState2("");
520
- const deferredThreadSearch = useDeferredValue(threadSearch);
521
- const deferredParticipantSearch = useDeferredValue(participantSearch);
522
- const deferredAgentSearch = useDeferredValue(agentSearch);
523
- const admin = useCopilotzAdmin({
524
- baseUrl: config.baseUrl,
525
- getRequestHeaders: config.getRequestHeaders,
526
- namespace: config.namespace,
527
- range: config.initialRange,
528
- interval: config.initialInterval,
529
- threadSearch: deferredThreadSearch,
530
- participantSearch: deferredParticipantSearch,
531
- agentSearch: deferredAgentSearch
532
- });
533
- const cards = [
534
- {
535
- label: config.labels.messagesCard,
536
- value: admin.overview?.messageTotals.total ?? 0,
537
- detail: `${admin.overview?.messageTotals.toolCallMessages ?? 0} tool-call messages`
538
- },
729
+ }
730
+ function SheetContent({
731
+ className,
732
+ children,
733
+ side = "right",
734
+ ...props
735
+ }) {
736
+ return /* @__PURE__ */ jsxs2(SheetPortal, { children: [
737
+ /* @__PURE__ */ jsx6(SheetOverlay, {}),
738
+ /* @__PURE__ */ jsxs2(
739
+ SheetPrimitive.Content,
740
+ {
741
+ "data-slot": "sheet-content",
742
+ "aria-describedby": void 0,
743
+ className: cn(
744
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
745
+ side === "right" && "data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
746
+ side === "left" && "data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
747
+ side === "top" && "data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
748
+ side === "bottom" && "data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
749
+ className
750
+ ),
751
+ ...props,
752
+ children: [
753
+ children,
754
+ /* @__PURE__ */ jsxs2(SheetPrimitive.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none", children: [
755
+ /* @__PURE__ */ jsx6(XIcon, { className: "size-4" }),
756
+ /* @__PURE__ */ jsx6("span", { className: "sr-only", children: "Close" })
757
+ ] })
758
+ ]
759
+ }
760
+ )
761
+ ] });
762
+ }
763
+ function SheetHeader({ className, ...props }) {
764
+ return /* @__PURE__ */ jsx6(
765
+ "div",
539
766
  {
540
- label: config.labels.activeThreadsCard,
541
- value: admin.overview?.threadTotals.active ?? 0,
542
- detail: `${admin.overview?.threadTotals.total ?? 0} total threads`
543
- },
767
+ "data-slot": "sheet-header",
768
+ className: cn("flex flex-col gap-1.5 p-4", className),
769
+ ...props
770
+ }
771
+ );
772
+ }
773
+ function SheetTitle({
774
+ className,
775
+ ...props
776
+ }) {
777
+ return /* @__PURE__ */ jsx6(
778
+ SheetPrimitive.Title,
544
779
  {
545
- label: config.labels.participantsCard,
546
- value: admin.overview?.participantTotals.total ?? 0,
547
- detail: `${admin.overview?.participantTotals.agents ?? 0} agents`
780
+ "data-slot": "sheet-title",
781
+ className: cn("text-foreground font-semibold", className),
782
+ ...props
783
+ }
784
+ );
785
+ }
786
+ function SheetDescription({
787
+ className,
788
+ ...props
789
+ }) {
790
+ return /* @__PURE__ */ jsx6(
791
+ SheetPrimitive.Description,
792
+ {
793
+ "data-slot": "sheet-description",
794
+ className: cn("text-muted-foreground text-sm", className),
795
+ ...props
796
+ }
797
+ );
798
+ }
799
+
800
+ // src/components/ui/sidebar.tsx
801
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
802
+ var SIDEBAR_COOKIE_NAME = "sidebar_state";
803
+ var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
804
+ var SIDEBAR_WIDTH = "16rem";
805
+ var SIDEBAR_WIDTH_MOBILE = "18rem";
806
+ var SIDEBAR_WIDTH_ICON = "3rem";
807
+ var SIDEBAR_KEYBOARD_SHORTCUT = "b";
808
+ var SidebarContext = React3.createContext(null);
809
+ function useSidebar() {
810
+ const context = React3.useContext(SidebarContext);
811
+ if (!context) {
812
+ throw new Error("useSidebar must be used within a SidebarProvider.");
813
+ }
814
+ return context;
815
+ }
816
+ function SidebarProvider({
817
+ defaultOpen = true,
818
+ open: openProp,
819
+ onOpenChange: setOpenProp,
820
+ className,
821
+ style,
822
+ children,
823
+ ...props
824
+ }) {
825
+ const isMobile = useIsMobile();
826
+ const [openMobile, setOpenMobile] = React3.useState(false);
827
+ const [_open, _setOpen] = React3.useState(defaultOpen);
828
+ const open = openProp ?? _open;
829
+ const setOpen = React3.useCallback(
830
+ (value) => {
831
+ const openState = typeof value === "function" ? value(open) : value;
832
+ if (setOpenProp) {
833
+ setOpenProp(openState);
834
+ } else {
835
+ _setOpen(openState);
836
+ }
837
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
548
838
  },
839
+ [setOpenProp, open]
840
+ );
841
+ const toggleSidebar = React3.useCallback(() => {
842
+ return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
843
+ }, [isMobile, setOpen, setOpenMobile]);
844
+ React3.useEffect(() => {
845
+ const handleKeyDown = (event) => {
846
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
847
+ event.preventDefault();
848
+ toggleSidebar();
849
+ }
850
+ };
851
+ window.addEventListener("keydown", handleKeyDown);
852
+ return () => window.removeEventListener("keydown", handleKeyDown);
853
+ }, [toggleSidebar]);
854
+ const state = open ? "expanded" : "collapsed";
855
+ const contextValue = React3.useMemo(
856
+ () => ({
857
+ state,
858
+ open,
859
+ setOpen,
860
+ isMobile,
861
+ openMobile,
862
+ setOpenMobile,
863
+ toggleSidebar
864
+ }),
865
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
866
+ );
867
+ return /* @__PURE__ */ jsx7(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx7(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx7(
868
+ "div",
549
869
  {
550
- label: config.labels.tokensCard,
551
- value: admin.overview?.llmTotals.totalTokens ?? 0,
552
- detail: `${admin.overview?.llmTotals.totalCalls ?? 0} calls`
870
+ "data-slot": "sidebar-wrapper",
871
+ style: {
872
+ "--sidebar-width": SIDEBAR_WIDTH,
873
+ "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
874
+ ...style
875
+ },
876
+ className: cn(
877
+ "group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
878
+ className
879
+ ),
880
+ ...props,
881
+ children
882
+ }
883
+ ) }) });
884
+ }
885
+ function Sidebar({
886
+ side = "left",
887
+ variant = "sidebar",
888
+ collapsible = "offcanvas",
889
+ className,
890
+ children,
891
+ ...props
892
+ }) {
893
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
894
+ if (collapsible === "none") {
895
+ return /* @__PURE__ */ jsx7(
896
+ "div",
897
+ {
898
+ "data-slot": "sidebar",
899
+ className: cn(
900
+ "bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
901
+ className
902
+ ),
903
+ ...props,
904
+ children
905
+ }
906
+ );
907
+ }
908
+ if (isMobile) {
909
+ return /* @__PURE__ */ jsx7(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ jsxs3(
910
+ SheetContent,
911
+ {
912
+ "data-sidebar": "sidebar",
913
+ "data-slot": "sidebar",
914
+ "data-mobile": "true",
915
+ className: "bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",
916
+ style: {
917
+ "--sidebar-width": SIDEBAR_WIDTH_MOBILE
918
+ },
919
+ side,
920
+ children: [
921
+ /* @__PURE__ */ jsxs3(SheetHeader, { className: "sr-only", children: [
922
+ /* @__PURE__ */ jsx7(SheetTitle, { children: "Sidebar" }),
923
+ /* @__PURE__ */ jsx7(SheetDescription, { children: "Displays the mobile sidebar." })
924
+ ] }),
925
+ /* @__PURE__ */ jsx7("div", { className: "flex h-full w-full flex-col", children })
926
+ ]
927
+ }
928
+ ) });
929
+ }
930
+ return /* @__PURE__ */ jsxs3(
931
+ "div",
932
+ {
933
+ className: "group peer text-sidebar-foreground hidden md:block",
934
+ "data-state": state,
935
+ "data-collapsible": state === "collapsed" ? collapsible : "",
936
+ "data-variant": variant,
937
+ "data-side": side,
938
+ "data-slot": "sidebar",
939
+ children: [
940
+ /* @__PURE__ */ jsx7(
941
+ "div",
942
+ {
943
+ "data-slot": "sidebar-gap",
944
+ className: cn(
945
+ "relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
946
+ "group-data-[collapsible=offcanvas]:w-0",
947
+ "group-data-[side=right]:rotate-180",
948
+ variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
949
+ )
950
+ }
951
+ ),
952
+ /* @__PURE__ */ jsx7(
953
+ "div",
954
+ {
955
+ "data-slot": "sidebar-container",
956
+ className: cn(
957
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
958
+ side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
959
+ variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
960
+ className
961
+ ),
962
+ ...props,
963
+ children: /* @__PURE__ */ jsx7(
964
+ "div",
965
+ {
966
+ "data-sidebar": "sidebar",
967
+ "data-slot": "sidebar-inner",
968
+ className: "bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm",
969
+ children
970
+ }
971
+ )
972
+ }
973
+ )
974
+ ]
975
+ }
976
+ );
977
+ }
978
+ function SidebarTrigger({
979
+ className,
980
+ onClick,
981
+ ...props
982
+ }) {
983
+ const { toggleSidebar } = useSidebar();
984
+ return /* @__PURE__ */ jsxs3(
985
+ Button,
986
+ {
987
+ "data-sidebar": "trigger",
988
+ "data-slot": "sidebar-trigger",
989
+ variant: "ghost",
990
+ size: "icon",
991
+ className: cn("size-7", className),
992
+ onClick: (event) => {
993
+ onClick?.(event);
994
+ toggleSidebar();
995
+ },
996
+ ...props,
997
+ children: [
998
+ /* @__PURE__ */ jsx7(PanelLeftIcon, {}),
999
+ /* @__PURE__ */ jsx7("span", { className: "sr-only", children: "Toggle Sidebar" })
1000
+ ]
1001
+ }
1002
+ );
1003
+ }
1004
+ function SidebarRail({ className, ...props }) {
1005
+ const { toggleSidebar } = useSidebar();
1006
+ return /* @__PURE__ */ jsx7(
1007
+ "button",
1008
+ {
1009
+ "data-sidebar": "rail",
1010
+ "data-slot": "sidebar-rail",
1011
+ "aria-label": "Toggle Sidebar",
1012
+ tabIndex: -1,
1013
+ onClick: toggleSidebar,
1014
+ title: "Toggle Sidebar",
1015
+ className: cn(
1016
+ "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex",
1017
+ "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
1018
+ "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
1019
+ "hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
1020
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
1021
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
1022
+ className
1023
+ ),
1024
+ ...props
1025
+ }
1026
+ );
1027
+ }
1028
+ function SidebarInset({ className, ...props }) {
1029
+ return /* @__PURE__ */ jsx7(
1030
+ "main",
1031
+ {
1032
+ "data-slot": "sidebar-inset",
1033
+ className: cn(
1034
+ "bg-background relative flex w-full flex-1 flex-col",
1035
+ "md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
1036
+ className
1037
+ ),
1038
+ ...props
1039
+ }
1040
+ );
1041
+ }
1042
+ function SidebarHeader({ className, ...props }) {
1043
+ return /* @__PURE__ */ jsx7(
1044
+ "div",
1045
+ {
1046
+ "data-slot": "sidebar-header",
1047
+ "data-sidebar": "header",
1048
+ className: cn("flex flex-col gap-2 p-2", className),
1049
+ ...props
1050
+ }
1051
+ );
1052
+ }
1053
+ function SidebarFooter({ className, ...props }) {
1054
+ return /* @__PURE__ */ jsx7(
1055
+ "div",
1056
+ {
1057
+ "data-slot": "sidebar-footer",
1058
+ "data-sidebar": "footer",
1059
+ className: cn("flex flex-col gap-2 p-2", className),
1060
+ ...props
1061
+ }
1062
+ );
1063
+ }
1064
+ function SidebarSeparator({
1065
+ className,
1066
+ ...props
1067
+ }) {
1068
+ return /* @__PURE__ */ jsx7(
1069
+ Separator,
1070
+ {
1071
+ "data-slot": "sidebar-separator",
1072
+ "data-sidebar": "separator",
1073
+ className: cn("bg-sidebar-border mx-2 w-auto", className),
1074
+ ...props
1075
+ }
1076
+ );
1077
+ }
1078
+ function SidebarContent({ className, ...props }) {
1079
+ return /* @__PURE__ */ jsx7(
1080
+ "div",
1081
+ {
1082
+ "data-slot": "sidebar-content",
1083
+ "data-sidebar": "content",
1084
+ className: cn(
1085
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
1086
+ className
1087
+ ),
1088
+ ...props
1089
+ }
1090
+ );
1091
+ }
1092
+ function SidebarGroup({ className, ...props }) {
1093
+ return /* @__PURE__ */ jsx7(
1094
+ "div",
1095
+ {
1096
+ "data-slot": "sidebar-group",
1097
+ "data-sidebar": "group",
1098
+ className: cn("relative flex w-full min-w-0 flex-col p-2", className),
1099
+ ...props
1100
+ }
1101
+ );
1102
+ }
1103
+ function SidebarGroupLabel({
1104
+ className,
1105
+ asChild = false,
1106
+ ...props
1107
+ }) {
1108
+ const Comp = asChild ? Slot2 : "div";
1109
+ return /* @__PURE__ */ jsx7(
1110
+ Comp,
1111
+ {
1112
+ "data-slot": "sidebar-group-label",
1113
+ "data-sidebar": "group-label",
1114
+ className: cn(
1115
+ "text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
1116
+ "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
1117
+ className
1118
+ ),
1119
+ ...props
1120
+ }
1121
+ );
1122
+ }
1123
+ function SidebarGroupContent({
1124
+ className,
1125
+ ...props
1126
+ }) {
1127
+ return /* @__PURE__ */ jsx7(
1128
+ "div",
1129
+ {
1130
+ "data-slot": "sidebar-group-content",
1131
+ "data-sidebar": "group-content",
1132
+ className: cn("w-full text-sm", className),
1133
+ ...props
1134
+ }
1135
+ );
1136
+ }
1137
+ function SidebarMenu({ className, ...props }) {
1138
+ return /* @__PURE__ */ jsx7(
1139
+ "ul",
1140
+ {
1141
+ "data-slot": "sidebar-menu",
1142
+ "data-sidebar": "menu",
1143
+ className: cn("flex w-full min-w-0 flex-col gap-1", className),
1144
+ ...props
1145
+ }
1146
+ );
1147
+ }
1148
+ function SidebarMenuItem({ className, ...props }) {
1149
+ return /* @__PURE__ */ jsx7(
1150
+ "li",
1151
+ {
1152
+ "data-slot": "sidebar-menu-item",
1153
+ "data-sidebar": "menu-item",
1154
+ className: cn("group/menu-item relative", className),
1155
+ ...props
1156
+ }
1157
+ );
1158
+ }
1159
+ var sidebarMenuButtonVariants = cva2(
1160
+ "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
1161
+ {
1162
+ variants: {
1163
+ variant: {
1164
+ default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
1165
+ outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
1166
+ },
1167
+ size: {
1168
+ default: "h-8 text-sm",
1169
+ sm: "h-7 text-xs",
1170
+ lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
1171
+ }
553
1172
  },
1173
+ defaultVariants: {
1174
+ variant: "default",
1175
+ size: "default"
1176
+ }
1177
+ }
1178
+ );
1179
+ function SidebarMenuButton({
1180
+ asChild = false,
1181
+ isActive = false,
1182
+ variant = "default",
1183
+ size = "default",
1184
+ tooltip,
1185
+ className,
1186
+ ...props
1187
+ }) {
1188
+ const Comp = asChild ? Slot2 : "button";
1189
+ const { isMobile, state } = useSidebar();
1190
+ const button = /* @__PURE__ */ jsx7(
1191
+ Comp,
554
1192
  {
555
- label: config.labels.queueCard,
556
- value: admin.overview?.queueTotals.pending ?? 0,
557
- detail: `${admin.overview?.queueTotals.failed ?? 0} failed`
1193
+ "data-slot": "sidebar-menu-button",
1194
+ "data-sidebar": "menu-button",
1195
+ "data-size": size,
1196
+ "data-active": isActive,
1197
+ className: cn(sidebarMenuButtonVariants({ variant, size }), className),
1198
+ ...props
558
1199
  }
559
- ];
560
- if (admin.isLoading && !admin.overview) {
561
- return /* @__PURE__ */ jsx6(Card, { className: cn("border-border", className), children: /* @__PURE__ */ jsx6(CardContent, { className: "text-muted-foreground", children: config.labels.loading }) });
1200
+ );
1201
+ if (!tooltip) {
1202
+ return button;
562
1203
  }
563
- if (admin.error && !admin.overview) {
564
- return /* @__PURE__ */ jsx6(Card, { className: cn("border-destructive/50 bg-destructive/10", className), children: /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-4", children: [
565
- /* @__PURE__ */ jsx6("p", { className: "text-base font-semibold text-destructive", children: admin.error.message }),
566
- /* @__PURE__ */ jsx6(
567
- Button,
1204
+ if (typeof tooltip === "string") {
1205
+ tooltip = {
1206
+ children: tooltip
1207
+ };
1208
+ }
1209
+ return /* @__PURE__ */ jsxs3(Tooltip, { children: [
1210
+ /* @__PURE__ */ jsx7(TooltipTrigger, { asChild: true, children: button }),
1211
+ /* @__PURE__ */ jsx7(
1212
+ TooltipContent,
1213
+ {
1214
+ side: "right",
1215
+ align: "center",
1216
+ hidden: state !== "collapsed" || isMobile,
1217
+ ...tooltip
1218
+ }
1219
+ )
1220
+ ] });
1221
+ }
1222
+
1223
+ // src/components/layout/AdminSidebar.tsx
1224
+ import {
1225
+ LayoutDashboard,
1226
+ MessageSquare,
1227
+ Users,
1228
+ Bot,
1229
+ Activity,
1230
+ Database,
1231
+ ChevronsUpDown
1232
+ } from "lucide-react";
1233
+
1234
+ // src/components/ui/select.tsx
1235
+ import * as React4 from "react";
1236
+ import * as SelectPrimitive from "@radix-ui/react-select";
1237
+ import { Check, ChevronDown, ChevronUp } from "lucide-react";
1238
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1239
+ var Select = SelectPrimitive.Root;
1240
+ var SelectValue = SelectPrimitive.Value;
1241
+ var SelectTrigger = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs4(
1242
+ SelectPrimitive.Trigger,
1243
+ {
1244
+ ref,
1245
+ className: cn(
1246
+ "flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none transition-colors placeholder:text-muted-foreground focus:ring-2 focus:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50",
1247
+ className
1248
+ ),
1249
+ ...props,
1250
+ children: [
1251
+ children,
1252
+ /* @__PURE__ */ jsx8(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx8(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
1253
+ ]
1254
+ }
1255
+ ));
1256
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1257
+ var SelectContent = React4.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx8(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs4(
1258
+ SelectPrimitive.Content,
1259
+ {
1260
+ ref,
1261
+ className: cn(
1262
+ "relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md",
1263
+ position === "popper" && "translate-y-1",
1264
+ className
1265
+ ),
1266
+ position,
1267
+ ...props,
1268
+ children: [
1269
+ /* @__PURE__ */ jsx8(SelectPrimitive.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsx8(ChevronUp, { className: "h-4 w-4" }) }),
1270
+ /* @__PURE__ */ jsx8(
1271
+ SelectPrimitive.Viewport,
568
1272
  {
569
- variant: "destructive",
570
- onClick: () => void admin.refresh(),
571
- children: config.labels.retry
1273
+ className: cn(
1274
+ "p-1",
1275
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
1276
+ ),
1277
+ children
572
1278
  }
573
- )
574
- ] }) });
1279
+ ),
1280
+ /* @__PURE__ */ jsx8(SelectPrimitive.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsx8(ChevronDown, { className: "h-4 w-4" }) })
1281
+ ]
1282
+ }
1283
+ ) }));
1284
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
1285
+ var SelectItem = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs4(
1286
+ SelectPrimitive.Item,
1287
+ {
1288
+ ref,
1289
+ className: cn(
1290
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
1291
+ className
1292
+ ),
1293
+ ...props,
1294
+ children: [
1295
+ /* @__PURE__ */ jsx8(SelectPrimitive.ItemText, { children }),
1296
+ /* @__PURE__ */ jsx8(SelectPrimitive.ItemIndicator, { className: "absolute right-2 inline-flex items-center justify-center", children: /* @__PURE__ */ jsx8(Check, { className: "h-4 w-4" }) })
1297
+ ]
575
1298
  }
576
- const isEmpty = cards.every((card) => card.value === 0) && admin.activity.length === 0 && admin.threads.length === 0 && admin.participants.length === 0 && admin.agents.length === 0;
577
- return /* @__PURE__ */ jsx6(Card, { className: cn("gap-0 overflow-hidden py-0", className), children: /* @__PURE__ */ jsxs2(CardContent, { className: "space-y-6 p-6", children: [
578
- /* @__PURE__ */ jsxs2("header", { className: "flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between", children: [
579
- /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
580
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
581
- config.branding.logo ? /* @__PURE__ */ jsx6("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl border bg-background shadow-sm", children: config.branding.logo }) : null,
582
- /* @__PURE__ */ jsxs2("div", { children: [
583
- /* @__PURE__ */ jsx6("h2", { className: "text-2xl font-semibold tracking-tight", children: config.branding.title }),
584
- /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: config.branding.subtitle })
1299
+ ));
1300
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
1301
+
1302
+ // src/components/layout/AdminSidebar.tsx
1303
+ import { Fragment, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1304
+ var NAV_ITEMS = [
1305
+ { page: "dashboard", label: "Dashboard", icon: LayoutDashboard },
1306
+ { page: "threads", label: "Threads", icon: MessageSquare, featureKey: "showThreads" },
1307
+ { page: "participants", label: "Participants", icon: Users, featureKey: "showParticipants" },
1308
+ { page: "agents", label: "Agents", icon: Bot, featureKey: "showAgents" },
1309
+ { page: "events", label: "Events", icon: Activity, featureKey: "showEvents" }
1310
+ ];
1311
+ var AdminSidebar = ({
1312
+ config,
1313
+ currentPage,
1314
+ currentRoute,
1315
+ onNavigate,
1316
+ onNavigateRoute,
1317
+ collections,
1318
+ namespace,
1319
+ onNamespaceChange
1320
+ }) => {
1321
+ const visibleItems = NAV_ITEMS.filter(
1322
+ (item) => !item.featureKey || config.features[item.featureKey]
1323
+ );
1324
+ const showCollections = config.features.showCollections && collections.length > 0;
1325
+ return /* @__PURE__ */ jsxs5(Sidebar, { collapsible: config.sidebar.collapsible, children: [
1326
+ /* @__PURE__ */ jsx9(SidebarHeader, { children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 px-2 py-3", children: [
1327
+ /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-center shrink-0", children: config.branding.logo || /* @__PURE__ */ jsx9("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx9(LayoutDashboard, { className: "h-4 w-4" }) }) }),
1328
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-col min-w-0 group-data-[collapsible=icon]:hidden", children: [
1329
+ /* @__PURE__ */ jsx9("span", { className: "text-sm font-semibold truncate", children: config.branding.title }),
1330
+ config.branding.subtitle && /* @__PURE__ */ jsx9("span", { className: "text-xs text-muted-foreground truncate", children: config.branding.subtitle })
1331
+ ] })
1332
+ ] }) }),
1333
+ /* @__PURE__ */ jsxs5(SidebarContent, { children: [
1334
+ /* @__PURE__ */ jsxs5(SidebarGroup, { children: [
1335
+ /* @__PURE__ */ jsx9(SidebarGroupLabel, { className: "group-data-[collapsible=icon]:hidden", children: "Navigation" }),
1336
+ /* @__PURE__ */ jsx9(SidebarGroupContent, { children: /* @__PURE__ */ jsx9(SidebarMenu, { children: visibleItems.map((item) => {
1337
+ const Icon2 = item.icon;
1338
+ const label = config.labels[`${item.page}Title`] || item.label;
1339
+ return /* @__PURE__ */ jsx9(SidebarMenuItem, { children: /* @__PURE__ */ jsxs5(
1340
+ SidebarMenuButton,
1341
+ {
1342
+ isActive: currentPage === item.page,
1343
+ onClick: () => onNavigate(item.page),
1344
+ tooltip: label,
1345
+ children: [
1346
+ /* @__PURE__ */ jsx9(Icon2, {}),
1347
+ /* @__PURE__ */ jsx9("span", { children: label })
1348
+ ]
1349
+ }
1350
+ ) }, item.page);
1351
+ }) }) })
1352
+ ] }),
1353
+ showCollections && /* @__PURE__ */ jsxs5(Fragment, { children: [
1354
+ /* @__PURE__ */ jsx9(SidebarSeparator, {}),
1355
+ /* @__PURE__ */ jsxs5(SidebarGroup, { children: [
1356
+ /* @__PURE__ */ jsx9(SidebarGroupLabel, { className: "group-data-[collapsible=icon]:hidden", children: config.labels.collectionsTitle }),
1357
+ /* @__PURE__ */ jsx9(SidebarGroupContent, { children: /* @__PURE__ */ jsx9(SidebarMenu, { children: collections.map((col) => /* @__PURE__ */ jsx9(SidebarMenuItem, { children: /* @__PURE__ */ jsxs5(
1358
+ SidebarMenuButton,
1359
+ {
1360
+ isActive: currentRoute.page === "collection-items" && currentRoute.collection === col,
1361
+ onClick: () => onNavigateRoute({ page: "collection-items", collection: col }),
1362
+ tooltip: col,
1363
+ children: [
1364
+ /* @__PURE__ */ jsx9(Database, {}),
1365
+ /* @__PURE__ */ jsx9("span", { className: "capitalize", children: col })
1366
+ ]
1367
+ }
1368
+ ) }, col)) }) })
1369
+ ] })
1370
+ ] })
1371
+ ] }),
1372
+ /* @__PURE__ */ jsxs5(SidebarFooter, { children: [
1373
+ /* @__PURE__ */ jsxs5("div", { className: "group-data-[collapsible=icon]:hidden", children: [
1374
+ /* @__PURE__ */ jsx9("label", { className: "text-xs font-medium text-muted-foreground mb-1 block px-2", children: "Namespace" }),
1375
+ /* @__PURE__ */ jsxs5(Select, { value: namespace || "__all__", onValueChange: (v) => onNamespaceChange(v === "__all__" ? "" : v), children: [
1376
+ /* @__PURE__ */ jsx9(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx9(SelectValue, { placeholder: "All namespaces" }) }),
1377
+ /* @__PURE__ */ jsxs5(SelectContent, { children: [
1378
+ /* @__PURE__ */ jsx9(SelectItem, { value: "__all__", children: "All namespaces" }),
1379
+ config.namespace && /* @__PURE__ */ jsx9(SelectItem, { value: config.namespace, children: config.namespace })
585
1380
  ] })
586
- ] }),
587
- config.namespace ? /* @__PURE__ */ jsxs2("p", { className: "text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground", children: [
588
- "Namespace: ",
589
- config.namespace
590
- ] }) : null
1381
+ ] })
1382
+ ] }),
1383
+ /* @__PURE__ */ jsx9("div", { className: "hidden group-data-[collapsible=icon]:flex justify-center", children: /* @__PURE__ */ jsx9(ChevronsUpDown, { className: "h-4 w-4 text-muted-foreground" }) })
1384
+ ] }),
1385
+ /* @__PURE__ */ jsx9(SidebarRail, {})
1386
+ ] });
1387
+ };
1388
+
1389
+ // src/components/layout/AdminHeader.tsx
1390
+ import { RefreshCw } from "lucide-react";
1391
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
1392
+ var PAGE_TITLES = {
1393
+ dashboard: "Dashboard",
1394
+ threads: "Threads",
1395
+ "thread-detail": "Thread Detail",
1396
+ participants: "Participants",
1397
+ "participant-detail": "Participant Detail",
1398
+ agents: "Agents",
1399
+ "agent-detail": "Agent Detail",
1400
+ "collection-items": "Collection",
1401
+ "collection-item-detail": "Item Detail",
1402
+ events: "Events"
1403
+ };
1404
+ var AdminHeader = ({
1405
+ config,
1406
+ currentRoute,
1407
+ range,
1408
+ interval,
1409
+ onRangeChange,
1410
+ onIntervalChange,
1411
+ onRefresh,
1412
+ isLoading
1413
+ }) => {
1414
+ let pageTitle = config.labels[`${currentRoute.page}Title`] || PAGE_TITLES[currentRoute.page] || currentRoute.page;
1415
+ if (currentRoute.page === "collection-items" && currentRoute.collection) {
1416
+ pageTitle = currentRoute.collection.charAt(0).toUpperCase() + currentRoute.collection.slice(1);
1417
+ }
1418
+ return /* @__PURE__ */ jsx10(Card, { className: "py-0 border-b rounded-none relative z-10 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80", children: /* @__PURE__ */ jsx10(CardHeader, { className: "p-2", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2", children: [
1419
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1", children: [
1420
+ /* @__PURE__ */ jsxs6(Tooltip, { children: [
1421
+ /* @__PURE__ */ jsx10(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(SidebarTrigger, { className: "-ml-1" }) }),
1422
+ /* @__PURE__ */ jsx10(TooltipContent, { children: "Toggle Sidebar" })
591
1423
  ] }),
592
- /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-2", children: [
593
- /* @__PURE__ */ jsx6(
1424
+ /* @__PURE__ */ jsx10("h1", { className: "text-sm font-medium ml-2", children: pageTitle })
1425
+ ] }),
1426
+ /* @__PURE__ */ jsx10("div", { className: "flex-1" }),
1427
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1", children: [
1428
+ currentRoute.page === "dashboard" && /* @__PURE__ */ jsxs6(Fragment2, { children: [
1429
+ /* @__PURE__ */ jsx10(
594
1430
  Button,
595
1431
  {
596
- variant: admin.filters.range === "24h" ? "default" : "outline",
1432
+ variant: range === "24h" ? "default" : "ghost",
597
1433
  size: "sm",
598
- onClick: () => admin.setRange("24h"),
1434
+ className: "h-7 text-xs",
1435
+ onClick: () => onRangeChange("24h"),
599
1436
  children: config.labels.range24h
600
1437
  }
601
1438
  ),
602
- /* @__PURE__ */ jsx6(
1439
+ /* @__PURE__ */ jsx10(
603
1440
  Button,
604
1441
  {
605
- variant: admin.filters.range === "7d" ? "default" : "outline",
1442
+ variant: range === "7d" ? "default" : "ghost",
606
1443
  size: "sm",
607
- onClick: () => admin.setRange("7d"),
1444
+ className: "h-7 text-xs",
1445
+ onClick: () => onRangeChange("7d"),
608
1446
  children: config.labels.range7d
609
1447
  }
610
1448
  ),
611
- /* @__PURE__ */ jsx6(
1449
+ /* @__PURE__ */ jsx10(
612
1450
  Button,
613
1451
  {
614
- variant: admin.filters.range === "30d" ? "default" : "outline",
1452
+ variant: range === "30d" ? "default" : "ghost",
615
1453
  size: "sm",
616
- onClick: () => admin.setRange("30d"),
1454
+ className: "h-7 text-xs",
1455
+ onClick: () => onRangeChange("30d"),
617
1456
  children: config.labels.range30d
618
1457
  }
619
1458
  ),
620
- /* @__PURE__ */ jsxs2(
1459
+ /* @__PURE__ */ jsxs6(
621
1460
  Select,
622
1461
  {
623
- value: admin.filters.interval,
624
- onValueChange: (v) => admin.setInterval(v),
1462
+ value: interval,
1463
+ onValueChange: (v) => onIntervalChange(v),
625
1464
  children: [
626
- /* @__PURE__ */ jsx6(SelectTrigger, { className: "h-8 w-[110px]", children: /* @__PURE__ */ jsx6(SelectValue, {}) }),
627
- /* @__PURE__ */ jsxs2(SelectContent, { children: [
628
- /* @__PURE__ */ jsx6(SelectItem, { value: "hour", children: config.labels.intervalHour }),
629
- /* @__PURE__ */ jsx6(SelectItem, { value: "day", children: config.labels.intervalDay })
1465
+ /* @__PURE__ */ jsx10(SelectTrigger, { className: "h-7 w-[90px] text-xs", children: /* @__PURE__ */ jsx10(SelectValue, {}) }),
1466
+ /* @__PURE__ */ jsxs6(SelectContent, { children: [
1467
+ /* @__PURE__ */ jsx10(SelectItem, { value: "hour", children: config.labels.intervalHour }),
1468
+ /* @__PURE__ */ jsx10(SelectItem, { value: "day", children: config.labels.intervalDay })
630
1469
  ] })
631
1470
  ]
632
1471
  }
633
- ),
634
- /* @__PURE__ */ jsx6(
1472
+ )
1473
+ ] }),
1474
+ /* @__PURE__ */ jsxs6(Tooltip, { children: [
1475
+ /* @__PURE__ */ jsx10(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(
635
1476
  Button,
636
1477
  {
637
- variant: "outline",
638
- size: "sm",
639
- onClick: () => void admin.refresh(),
640
- children: config.labels.refresh
1478
+ variant: "ghost",
1479
+ size: "icon",
1480
+ className: "h-7 w-7",
1481
+ onClick: onRefresh,
1482
+ disabled: isLoading,
1483
+ children: /* @__PURE__ */ jsx10(
1484
+ RefreshCw,
1485
+ {
1486
+ className: `h-4 w-4 ${isLoading ? "animate-spin" : ""}`
1487
+ }
1488
+ )
641
1489
  }
642
- ),
643
- config.branding.actions
644
- ] })
1490
+ ) }),
1491
+ /* @__PURE__ */ jsx10(TooltipContent, { children: config.labels.refresh })
1492
+ ] }),
1493
+ config.branding.actions
1494
+ ] })
1495
+ ] }) }) });
1496
+ };
1497
+
1498
+ // src/components/ui/badge.tsx
1499
+ import { Slot as Slot3 } from "@radix-ui/react-slot";
1500
+ import { cva as cva3 } from "class-variance-authority";
1501
+ import { jsx as jsx11 } from "react/jsx-runtime";
1502
+ var badgeVariants = cva3(
1503
+ "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
1504
+ {
1505
+ variants: {
1506
+ variant: {
1507
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
1508
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
1509
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
1510
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
1511
+ }
1512
+ },
1513
+ defaultVariants: {
1514
+ variant: "default"
1515
+ }
1516
+ }
1517
+ );
1518
+ function Badge({
1519
+ className,
1520
+ variant,
1521
+ asChild = false,
1522
+ ...props
1523
+ }) {
1524
+ const Comp = asChild ? Slot3 : "span";
1525
+ return /* @__PURE__ */ jsx11(
1526
+ Comp,
1527
+ {
1528
+ "data-slot": "badge",
1529
+ className: cn(badgeVariants({ variant }), className),
1530
+ ...props
1531
+ }
1532
+ );
1533
+ }
1534
+
1535
+ // src/components/views/DashboardView.tsx
1536
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1537
+ var DashboardView = ({
1538
+ config,
1539
+ overview,
1540
+ activity,
1541
+ threads,
1542
+ participants,
1543
+ agents,
1544
+ interval,
1545
+ threadSearch,
1546
+ participantSearch,
1547
+ agentSearch,
1548
+ onThreadSearchChange,
1549
+ onParticipantSearchChange,
1550
+ onAgentSearchChange,
1551
+ onThreadClick
1552
+ }) => {
1553
+ const cards = [
1554
+ {
1555
+ label: config.labels.messagesCard,
1556
+ value: overview?.messageTotals.total ?? 0,
1557
+ detail: `${overview?.messageTotals.toolCallMessages ?? 0} tool-call messages`
1558
+ },
1559
+ {
1560
+ label: config.labels.activeThreadsCard,
1561
+ value: overview?.threadTotals.active ?? 0,
1562
+ detail: `${overview?.threadTotals.total ?? 0} total threads`
1563
+ },
1564
+ {
1565
+ label: config.labels.participantsCard,
1566
+ value: overview?.participantTotals.total ?? 0,
1567
+ detail: `${overview?.participantTotals.agents ?? 0} agents`
1568
+ },
1569
+ {
1570
+ label: config.labels.tokensCard,
1571
+ value: overview?.llmTotals.totalTokens ?? 0,
1572
+ detail: `${overview?.llmTotals.totalCalls ?? 0} calls`
1573
+ },
1574
+ {
1575
+ label: config.labels.queueCard,
1576
+ value: overview?.queueTotals.pending ?? 0,
1577
+ detail: `${overview?.queueTotals.failed ?? 0} failed`
1578
+ }
1579
+ ];
1580
+ const isEmpty = cards.every((card) => card.value === 0) && activity.length === 0 && threads.length === 0 && participants.length === 0 && agents.length === 0;
1581
+ return /* @__PURE__ */ jsxs7("div", { className: "space-y-6", children: [
1582
+ isEmpty && /* @__PURE__ */ jsxs7("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
1583
+ /* @__PURE__ */ jsx12("h3", { className: "text-lg font-semibold", children: config.labels.emptyTitle }),
1584
+ /* @__PURE__ */ jsx12("p", { className: "mt-2 text-sm text-muted-foreground", children: config.labels.emptyDescription })
645
1585
  ] }),
646
- isEmpty ? /* @__PURE__ */ jsxs2("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
647
- /* @__PURE__ */ jsx6("h3", { className: "text-lg font-semibold", children: config.labels.emptyTitle }),
648
- /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm text-muted-foreground", children: config.labels.emptyDescription })
649
- ] }) : null,
650
- config.features.showOverview ? /* @__PURE__ */ jsxs2("section", { className: "space-y-4", children: [
651
- /* @__PURE__ */ jsx6(SectionHeading, { title: config.labels.overviewTitle }),
652
- /* @__PURE__ */ jsx6("div", { className: "grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-5", children: cards.map((card) => /* @__PURE__ */ jsxs2(
1586
+ config.features.showOverview && /* @__PURE__ */ jsxs7("section", { className: "space-y-4", children: [
1587
+ /* @__PURE__ */ jsx12(SectionHeading, { title: config.labels.overviewTitle }),
1588
+ /* @__PURE__ */ jsx12("div", { className: "grid grid-cols-2 gap-4 md:grid-cols-3 lg:grid-cols-5", children: cards.map((card) => /* @__PURE__ */ jsxs7(
653
1589
  "div",
654
1590
  {
655
- className: "rounded-xl border bg-background p-5 shadow-sm",
1591
+ className: "rounded-xl border bg-card p-5 shadow-sm",
656
1592
  children: [
657
- /* @__PURE__ */ jsx6("p", { className: "text-sm font-medium text-muted-foreground", children: card.label }),
658
- /* @__PURE__ */ jsx6("p", { className: "mt-3 text-3xl font-semibold tracking-tight", children: formatNumber(card.value) }),
659
- /* @__PURE__ */ jsx6("p", { className: "mt-2 text-xs text-muted-foreground", children: card.detail })
1593
+ /* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-muted-foreground", children: card.label }),
1594
+ /* @__PURE__ */ jsx12("p", { className: "mt-3 text-3xl font-semibold tracking-tight", children: formatNumber(card.value) }),
1595
+ /* @__PURE__ */ jsx12("p", { className: "mt-2 text-xs text-muted-foreground", children: card.detail })
660
1596
  ]
661
1597
  },
662
1598
  card.label
663
1599
  )) })
664
- ] }) : null,
665
- config.features.showActivity ? /* @__PURE__ */ jsxs2("section", { className: "space-y-4", children: [
666
- /* @__PURE__ */ jsx6(SectionHeading, { title: config.labels.activityTitle }),
667
- /* @__PURE__ */ jsx6(
1600
+ ] }),
1601
+ config.features.showActivity && /* @__PURE__ */ jsxs7("section", { className: "space-y-4", children: [
1602
+ /* @__PURE__ */ jsx12(SectionHeading, { title: config.labels.activityTitle }),
1603
+ /* @__PURE__ */ jsx12(
668
1604
  ActivityChart,
669
1605
  {
670
- interval: admin.filters.interval,
1606
+ interval,
671
1607
  labels: config.labels,
672
1608
  maxBars: config.ui.maxActivityBars,
673
- points: admin.activity
1609
+ points: activity
674
1610
  }
675
1611
  )
676
- ] }) : null,
677
- /* @__PURE__ */ jsxs2("div", { className: "grid gap-6 lg:grid-cols-3", children: [
678
- config.features.showThreads ? /* @__PURE__ */ jsx6(
1612
+ ] }),
1613
+ /* @__PURE__ */ jsxs7("div", { className: "grid gap-6 lg:grid-cols-3", children: [
1614
+ config.features.showThreads && /* @__PURE__ */ jsx12(
679
1615
  DataTable,
680
1616
  {
681
- rows: admin.threads,
1617
+ rows: threads,
682
1618
  searchPlaceholder: config.labels.threadSearchPlaceholder,
683
1619
  searchValue: threadSearch,
684
- setSearchValue: setThreadSearch,
1620
+ setSearchValue: onThreadSearchChange,
685
1621
  title: config.labels.threadsTitle,
686
- children: /* @__PURE__ */ jsx6(ThreadsTable, { rows: admin.threads, labels: config.labels })
1622
+ children: /* @__PURE__ */ jsx12(
1623
+ ThreadsTable,
1624
+ {
1625
+ rows: threads,
1626
+ labels: config.labels,
1627
+ onThreadClick
1628
+ }
1629
+ )
687
1630
  }
688
- ) : null,
689
- config.features.showParticipants ? /* @__PURE__ */ jsx6(
1631
+ ),
1632
+ config.features.showParticipants && /* @__PURE__ */ jsx12(
690
1633
  DataTable,
691
1634
  {
692
- rows: admin.participants,
1635
+ rows: participants,
693
1636
  searchPlaceholder: config.labels.participantSearchPlaceholder,
694
1637
  searchValue: participantSearch,
695
- setSearchValue: setParticipantSearch,
1638
+ setSearchValue: onParticipantSearchChange,
696
1639
  title: config.labels.participantsTitle,
697
- children: /* @__PURE__ */ jsx6(
698
- ParticipantsTable,
699
- {
700
- rows: admin.participants,
701
- labels: config.labels
702
- }
703
- )
1640
+ children: /* @__PURE__ */ jsx12(ParticipantsTable, { rows: participants, labels: config.labels })
704
1641
  }
705
- ) : null,
706
- config.features.showAgents ? /* @__PURE__ */ jsx6(
1642
+ ),
1643
+ config.features.showAgents && /* @__PURE__ */ jsx12(
707
1644
  DataTable,
708
1645
  {
709
- rows: admin.agents,
1646
+ rows: agents,
710
1647
  searchPlaceholder: config.labels.agentSearchPlaceholder,
711
1648
  searchValue: agentSearch,
712
- setSearchValue: setAgentSearch,
1649
+ setSearchValue: onAgentSearchChange,
713
1650
  title: config.labels.agentsTitle,
714
- children: /* @__PURE__ */ jsx6(AgentsTable, { rows: admin.agents, labels: config.labels })
1651
+ children: /* @__PURE__ */ jsx12(AgentsTable, { rows: agents, labels: config.labels })
715
1652
  }
716
- ) : null
1653
+ )
717
1654
  ] })
718
- ] }) });
1655
+ ] });
719
1656
  };
720
1657
  function SectionHeading({ title }) {
721
- return /* @__PURE__ */ jsx6("h3", { className: "text-lg font-semibold tracking-tight", children: title });
1658
+ return /* @__PURE__ */ jsx12("h3", { className: "text-lg font-semibold tracking-tight", children: title });
722
1659
  }
723
1660
  function ActivityChart(props) {
724
1661
  const trimmedPoints = props.points.slice(-props.maxBars);
@@ -726,12 +1663,12 @@ function ActivityChart(props) {
726
1663
  ...trimmedPoints.map((point) => point.messageCount),
727
1664
  1
728
1665
  );
729
- return /* @__PURE__ */ jsx6("div", { className: "rounded-xl border bg-background p-5 shadow-sm", children: trimmedPoints.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: props.labels.noResults }) : /* @__PURE__ */ jsx6("div", { className: "flex min-h-48 items-end gap-2", children: trimmedPoints.map((point) => /* @__PURE__ */ jsxs2(
1666
+ return /* @__PURE__ */ jsx12("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: trimmedPoints.length === 0 ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted-foreground", children: props.labels.noResults }) : /* @__PURE__ */ jsx12("div", { className: "flex min-h-48 items-end gap-2", children: trimmedPoints.map((point) => /* @__PURE__ */ jsxs7(
730
1667
  "div",
731
1668
  {
732
1669
  className: "flex min-w-0 flex-1 flex-col items-center gap-2",
733
1670
  children: [
734
- /* @__PURE__ */ jsx6("div", { className: "flex h-36 w-full items-end rounded-lg bg-muted px-1 pb-1", children: /* @__PURE__ */ jsx6(
1671
+ /* @__PURE__ */ jsx12("div", { className: "flex h-36 w-full items-end rounded-lg bg-muted px-1 pb-1", children: /* @__PURE__ */ jsx12(
735
1672
  "div",
736
1673
  {
737
1674
  className: "w-full rounded-md bg-primary transition-all",
@@ -740,9 +1677,9 @@ function ActivityChart(props) {
740
1677
  }
741
1678
  }
742
1679
  ) }),
743
- /* @__PURE__ */ jsxs2("div", { className: "text-center", children: [
744
- /* @__PURE__ */ jsx6("p", { className: "text-xs font-medium", children: formatBucket(point.bucket, props.interval) }),
745
- /* @__PURE__ */ jsxs2("p", { className: "text-[11px] text-muted-foreground", children: [
1680
+ /* @__PURE__ */ jsxs7("div", { className: "text-center", children: [
1681
+ /* @__PURE__ */ jsx12("p", { className: "text-xs font-medium", children: formatBucket(point.bucket, props.interval) }),
1682
+ /* @__PURE__ */ jsxs7("p", { className: "text-[11px] text-muted-foreground", children: [
746
1683
  formatNumber(point.messageCount),
747
1684
  " msg"
748
1685
  ] })
@@ -753,10 +1690,10 @@ function ActivityChart(props) {
753
1690
  )) }) });
754
1691
  }
755
1692
  function DataTable(props) {
756
- return /* @__PURE__ */ jsxs2("div", { className: "rounded-xl border bg-background p-5 shadow-sm", children: [
757
- /* @__PURE__ */ jsxs2("div", { className: "mb-4 flex items-center justify-between gap-3", children: [
758
- /* @__PURE__ */ jsx6(SectionHeading, { title: props.title }),
759
- /* @__PURE__ */ jsx6(
1693
+ return /* @__PURE__ */ jsxs7("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [
1694
+ /* @__PURE__ */ jsxs7("div", { className: "mb-4 flex items-center justify-between gap-3", children: [
1695
+ /* @__PURE__ */ jsx12(SectionHeading, { title: props.title }),
1696
+ /* @__PURE__ */ jsx12(
760
1697
  Input,
761
1698
  {
762
1699
  className: "h-8 w-full max-w-44",
@@ -766,24 +1703,29 @@ function DataTable(props) {
766
1703
  }
767
1704
  )
768
1705
  ] }),
769
- props.rows.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "text-sm text-muted-foreground", children: "No results" }) : props.children
1706
+ props.rows.length === 0 ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-muted-foreground", children: "No results" }) : props.children
770
1707
  ] });
771
1708
  }
772
1709
  function ThreadsTable({
773
1710
  rows,
774
- labels
1711
+ labels,
1712
+ onThreadClick
775
1713
  }) {
776
- return /* @__PURE__ */ jsx6("div", { className: "space-y-3", children: rows.map((thread) => /* @__PURE__ */ jsxs2(
1714
+ return /* @__PURE__ */ jsx12("div", { className: "space-y-3", children: rows.map((thread) => /* @__PURE__ */ jsxs7(
777
1715
  "div",
778
1716
  {
779
- className: "rounded-lg border bg-muted/50 p-4",
1717
+ className: cn(
1718
+ "rounded-lg border bg-muted/50 p-4",
1719
+ onThreadClick && "cursor-pointer hover:bg-muted transition-colors"
1720
+ ),
1721
+ onClick: () => onThreadClick?.(thread.threadId),
780
1722
  children: [
781
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
782
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
783
- /* @__PURE__ */ jsx6("p", { className: "font-medium", children: thread.name }),
784
- /* @__PURE__ */ jsx6("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: thread.summary ?? thread.lastMessagePreview ?? "No summary yet" })
1723
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start justify-between gap-3", children: [
1724
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
1725
+ /* @__PURE__ */ jsx12("p", { className: "font-medium", children: thread.name }),
1726
+ /* @__PURE__ */ jsx12("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: thread.summary ?? thread.lastMessagePreview ?? "No summary yet" })
785
1727
  ] }),
786
- /* @__PURE__ */ jsx6(
1728
+ /* @__PURE__ */ jsx12(
787
1729
  Badge,
788
1730
  {
789
1731
  variant: thread.status === "archived" ? "secondary" : "default",
@@ -791,16 +1733,16 @@ function ThreadsTable({
791
1733
  }
792
1734
  )
793
1735
  ] }),
794
- /* @__PURE__ */ jsxs2("div", { className: "mt-3 flex flex-wrap gap-3 text-xs text-muted-foreground", children: [
795
- /* @__PURE__ */ jsxs2("span", { children: [
1736
+ /* @__PURE__ */ jsxs7("div", { className: "mt-3 flex flex-wrap gap-3 text-xs text-muted-foreground", children: [
1737
+ /* @__PURE__ */ jsxs7("span", { children: [
796
1738
  formatNumber(thread.messageCount),
797
1739
  " messages"
798
1740
  ] }),
799
- /* @__PURE__ */ jsxs2("span", { children: [
1741
+ /* @__PURE__ */ jsxs7("span", { children: [
800
1742
  thread.participantIds.length,
801
1743
  " participants"
802
1744
  ] }),
803
- /* @__PURE__ */ jsx6("span", { children: formatDate(thread.lastActivityAt) })
1745
+ /* @__PURE__ */ jsx12("span", { children: formatDate(thread.lastActivityAt) })
804
1746
  ] })
805
1747
  ]
806
1748
  },
@@ -811,28 +1753,28 @@ function ParticipantsTable({
811
1753
  rows,
812
1754
  labels
813
1755
  }) {
814
- return /* @__PURE__ */ jsx6("div", { className: "space-y-3", children: rows.map((participant) => /* @__PURE__ */ jsxs2(
1756
+ return /* @__PURE__ */ jsx12("div", { className: "space-y-3", children: rows.map((participant) => /* @__PURE__ */ jsxs7(
815
1757
  "div",
816
1758
  {
817
1759
  className: "rounded-lg border bg-muted/50 p-4",
818
1760
  children: [
819
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
820
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
821
- /* @__PURE__ */ jsx6("p", { className: "font-medium", children: participant.displayName }),
822
- /* @__PURE__ */ jsx6("p", { className: "mt-1 text-xs uppercase tracking-[0.18em] text-muted-foreground", children: participant.participantType })
1761
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start justify-between gap-3", children: [
1762
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
1763
+ /* @__PURE__ */ jsx12("p", { className: "font-medium", children: participant.displayName }),
1764
+ /* @__PURE__ */ jsx12("p", { className: "mt-1 text-xs uppercase tracking-[0.18em] text-muted-foreground", children: participant.participantType })
823
1765
  ] }),
824
- /* @__PURE__ */ jsx6(Badge, { variant: "outline", children: participant.isGlobal ? labels.scopeGlobal : labels.scopeScoped })
1766
+ /* @__PURE__ */ jsx12(Badge, { variant: "outline", children: participant.isGlobal ? labels.scopeGlobal : labels.scopeScoped })
825
1767
  ] }),
826
- /* @__PURE__ */ jsxs2("div", { className: "mt-3 flex flex-wrap gap-3 text-xs text-muted-foreground", children: [
827
- /* @__PURE__ */ jsxs2("span", { children: [
1768
+ /* @__PURE__ */ jsxs7("div", { className: "mt-3 flex flex-wrap gap-3 text-xs text-muted-foreground", children: [
1769
+ /* @__PURE__ */ jsxs7("span", { children: [
828
1770
  formatNumber(participant.messageCount),
829
1771
  " messages"
830
1772
  ] }),
831
- /* @__PURE__ */ jsxs2("span", { children: [
1773
+ /* @__PURE__ */ jsxs7("span", { children: [
832
1774
  formatNumber(participant.threadCount),
833
1775
  " threads"
834
1776
  ] }),
835
- /* @__PURE__ */ jsx6("span", { children: formatDate(participant.lastActivityAt) })
1777
+ /* @__PURE__ */ jsx12("span", { children: formatDate(participant.lastActivityAt) })
836
1778
  ] })
837
1779
  ]
838
1780
  },
@@ -843,32 +1785,32 @@ function AgentsTable({
843
1785
  rows,
844
1786
  labels
845
1787
  }) {
846
- return /* @__PURE__ */ jsx6("div", { className: "space-y-3", children: rows.map((agent) => /* @__PURE__ */ jsxs2(
1788
+ return /* @__PURE__ */ jsx12("div", { className: "space-y-3", children: rows.map((agent) => /* @__PURE__ */ jsxs7(
847
1789
  "div",
848
1790
  {
849
1791
  className: "rounded-lg border bg-muted/50 p-4",
850
1792
  children: [
851
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
852
- /* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
853
- /* @__PURE__ */ jsx6("p", { className: "font-medium", children: agent.displayName }),
854
- /* @__PURE__ */ jsx6("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: agent.description ?? agent.agentId })
1793
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start justify-between gap-3", children: [
1794
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
1795
+ /* @__PURE__ */ jsx12("p", { className: "font-medium", children: agent.displayName }),
1796
+ /* @__PURE__ */ jsx12("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: agent.description ?? agent.agentId })
855
1797
  ] }),
856
- /* @__PURE__ */ jsx6(Badge, { variant: "outline", children: agent.isConfigured ? labels.configured : labels.unconfigured })
1798
+ /* @__PURE__ */ jsx12(Badge, { variant: "outline", children: agent.isConfigured ? labels.configured : labels.unconfigured })
857
1799
  ] }),
858
- /* @__PURE__ */ jsxs2("div", { className: "mt-3 grid grid-cols-2 gap-2 text-xs text-muted-foreground", children: [
859
- /* @__PURE__ */ jsxs2("span", { children: [
1800
+ /* @__PURE__ */ jsxs7("div", { className: "mt-3 grid grid-cols-2 gap-2 text-xs text-muted-foreground", children: [
1801
+ /* @__PURE__ */ jsxs7("span", { children: [
860
1802
  formatNumber(agent.messageCount),
861
1803
  " messages"
862
1804
  ] }),
863
- /* @__PURE__ */ jsxs2("span", { children: [
1805
+ /* @__PURE__ */ jsxs7("span", { children: [
864
1806
  formatNumber(agent.llmCallCount),
865
1807
  " LLM calls"
866
1808
  ] }),
867
- /* @__PURE__ */ jsxs2("span", { children: [
1809
+ /* @__PURE__ */ jsxs7("span", { children: [
868
1810
  formatNumber(agent.toolCallMessageCount),
869
1811
  " tool calls"
870
1812
  ] }),
871
- /* @__PURE__ */ jsxs2("span", { children: [
1813
+ /* @__PURE__ */ jsxs7("span", { children: [
872
1814
  formatNumber(agent.totalTokens),
873
1815
  " tokens"
874
1816
  ] })
@@ -904,15 +1846,1193 @@ function formatDate(value) {
904
1846
  function formatNumber(value) {
905
1847
  return new Intl.NumberFormat().format(value);
906
1848
  }
1849
+
1850
+ // src/components/views/ThreadsView.tsx
1851
+ import { Search, MessageSquare as MessageSquare2 } from "lucide-react";
1852
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1853
+ var ThreadsView = ({
1854
+ config,
1855
+ threads,
1856
+ searchValue,
1857
+ onSearchChange,
1858
+ onThreadClick
1859
+ }) => {
1860
+ return /* @__PURE__ */ jsxs8("div", { className: "space-y-4", children: [
1861
+ /* @__PURE__ */ jsxs8("div", { className: "relative max-w-sm", children: [
1862
+ /* @__PURE__ */ jsx13(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
1863
+ /* @__PURE__ */ jsx13(
1864
+ Input,
1865
+ {
1866
+ className: "pl-9",
1867
+ placeholder: config.labels.threadSearchPlaceholder,
1868
+ value: searchValue,
1869
+ onChange: (e) => onSearchChange(e.target.value)
1870
+ }
1871
+ )
1872
+ ] }),
1873
+ threads.length === 0 ? /* @__PURE__ */ jsxs8("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
1874
+ /* @__PURE__ */ jsx13(MessageSquare2, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
1875
+ /* @__PURE__ */ jsx13("p", { className: "mt-3 text-sm text-muted-foreground", children: searchValue ? config.labels.noResults : config.labels.emptyDescription })
1876
+ ] }) : /* @__PURE__ */ jsx13("div", { className: "space-y-2", children: threads.map((thread) => /* @__PURE__ */ jsxs8(
1877
+ "div",
1878
+ {
1879
+ className: "flex items-center gap-4 rounded-lg border bg-card p-4 transition-colors hover:bg-muted/50 cursor-pointer",
1880
+ onClick: () => onThreadClick?.(thread.threadId),
1881
+ children: [
1882
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 min-w-0", children: [
1883
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
1884
+ /* @__PURE__ */ jsx13("p", { className: "font-medium truncate", children: thread.name }),
1885
+ /* @__PURE__ */ jsx13(
1886
+ Badge,
1887
+ {
1888
+ variant: thread.status === "archived" ? "secondary" : "default",
1889
+ className: "shrink-0",
1890
+ children: thread.status === "archived" ? config.labels.statusArchived : config.labels.statusActive
1891
+ }
1892
+ )
1893
+ ] }),
1894
+ /* @__PURE__ */ jsx13("p", { className: "mt-1 text-sm text-muted-foreground truncate", children: thread.summary ?? thread.lastMessagePreview ?? "No summary yet" })
1895
+ ] }),
1896
+ /* @__PURE__ */ jsxs8("div", { className: "text-right text-xs text-muted-foreground shrink-0 space-y-1", children: [
1897
+ /* @__PURE__ */ jsxs8("p", { children: [
1898
+ formatNumber2(thread.messageCount),
1899
+ " messages"
1900
+ ] }),
1901
+ /* @__PURE__ */ jsxs8("p", { children: [
1902
+ thread.participantIds.length,
1903
+ " participants"
1904
+ ] }),
1905
+ /* @__PURE__ */ jsx13("p", { children: formatDate2(thread.lastActivityAt) })
1906
+ ] })
1907
+ ]
1908
+ },
1909
+ thread.threadId
1910
+ )) })
1911
+ ] });
1912
+ };
1913
+ function formatDate2(value) {
1914
+ if (!value) return "No activity";
1915
+ const date = new Date(value);
1916
+ if (Number.isNaN(date.getTime())) return value;
1917
+ return date.toLocaleString(void 0, {
1918
+ month: "short",
1919
+ day: "numeric",
1920
+ hour: "numeric",
1921
+ minute: "2-digit"
1922
+ });
1923
+ }
1924
+ function formatNumber2(value) {
1925
+ return new Intl.NumberFormat().format(value);
1926
+ }
1927
+
1928
+ // src/components/views/ThreadDetailView.tsx
1929
+ import { useCallback as useCallback3, useEffect as useEffect5, useState as useState4 } from "react";
1930
+ import {
1931
+ ArrowLeft,
1932
+ Bot as Bot2,
1933
+ ChevronUp as ChevronUp2,
1934
+ Loader2,
1935
+ User,
1936
+ Wrench,
1937
+ Cpu
1938
+ } from "lucide-react";
1939
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1940
+ var MESSAGES_PAGE_SIZE = 50;
1941
+ var ThreadDetailView = ({
1942
+ threadId,
1943
+ config,
1944
+ onBack
1945
+ }) => {
1946
+ const [thread, setThread] = useState4(null);
1947
+ const [messages, setMessages] = useState4([]);
1948
+ const [pageInfo, setPageInfo] = useState4(null);
1949
+ const [isLoading, setIsLoading] = useState4(true);
1950
+ const [isLoadingMore, setIsLoadingMore] = useState4(false);
1951
+ const [error, setError] = useState4(null);
1952
+ const fetchOptions = {
1953
+ baseUrl: config.baseUrl,
1954
+ getRequestHeaders: config.getRequestHeaders
1955
+ };
1956
+ const loadInitial = useCallback3(async () => {
1957
+ setIsLoading(true);
1958
+ setError(null);
1959
+ try {
1960
+ const [threadData, messagesData] = await Promise.all([
1961
+ fetchThreadDetail(threadId, fetchOptions),
1962
+ fetchThreadMessages(threadId, { limit: MESSAGES_PAGE_SIZE }, fetchOptions)
1963
+ ]);
1964
+ setThread(threadData);
1965
+ setMessages(messagesData.data);
1966
+ setPageInfo(messagesData.pageInfo);
1967
+ } catch (err) {
1968
+ setError(
1969
+ err instanceof Error ? err : new Error("Failed to load thread")
1970
+ );
1971
+ } finally {
1972
+ setIsLoading(false);
1973
+ }
1974
+ }, [threadId, config.baseUrl, config.getRequestHeaders]);
1975
+ useEffect5(() => {
1976
+ void loadInitial();
1977
+ }, [loadInitial]);
1978
+ const loadMore = useCallback3(async () => {
1979
+ if (!pageInfo?.hasMoreBefore || !pageInfo.oldestMessageId || isLoadingMore) {
1980
+ return;
1981
+ }
1982
+ setIsLoadingMore(true);
1983
+ try {
1984
+ const older = await fetchThreadMessages(
1985
+ threadId,
1986
+ { limit: MESSAGES_PAGE_SIZE, before: pageInfo.oldestMessageId },
1987
+ fetchOptions
1988
+ );
1989
+ setMessages((prev) => [...older.data, ...prev]);
1990
+ setPageInfo(older.pageInfo);
1991
+ } catch {
1992
+ } finally {
1993
+ setIsLoadingMore(false);
1994
+ }
1995
+ }, [threadId, pageInfo, isLoadingMore, config.baseUrl, config.getRequestHeaders]);
1996
+ if (isLoading) {
1997
+ return /* @__PURE__ */ jsx14("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx14(Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground" }) });
1998
+ }
1999
+ if (error) {
2000
+ return /* @__PURE__ */ jsxs9("div", { className: "space-y-4 py-10 text-center", children: [
2001
+ /* @__PURE__ */ jsx14("p", { className: "text-destructive font-medium", children: error.message }),
2002
+ /* @__PURE__ */ jsxs9("div", { className: "flex justify-center gap-2", children: [
2003
+ /* @__PURE__ */ jsxs9(Button, { variant: "outline", onClick: onBack, children: [
2004
+ /* @__PURE__ */ jsx14(ArrowLeft, { className: "mr-2 h-4 w-4" }),
2005
+ "Back"
2006
+ ] }),
2007
+ /* @__PURE__ */ jsx14(Button, { variant: "destructive", onClick: () => void loadInitial(), children: config.labels.retry })
2008
+ ] })
2009
+ ] });
2010
+ }
2011
+ return /* @__PURE__ */ jsxs9("div", { className: "space-y-6", children: [
2012
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-4", children: [
2013
+ /* @__PURE__ */ jsx14(
2014
+ Button,
2015
+ {
2016
+ variant: "ghost",
2017
+ size: "icon",
2018
+ className: "mt-1 shrink-0",
2019
+ onClick: onBack,
2020
+ children: /* @__PURE__ */ jsx14(ArrowLeft, { className: "h-4 w-4" })
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ jsxs9("div", { className: "flex-1 min-w-0", children: [
2024
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
2025
+ /* @__PURE__ */ jsx14("h2", { className: "text-xl font-semibold truncate", children: thread?.name ?? threadId }),
2026
+ /* @__PURE__ */ jsx14(
2027
+ Badge,
2028
+ {
2029
+ variant: thread?.status === "archived" ? "secondary" : "default",
2030
+ children: thread?.status === "archived" ? config.labels.statusArchived : config.labels.statusActive
2031
+ }
2032
+ )
2033
+ ] }),
2034
+ thread?.summary && /* @__PURE__ */ jsx14("p", { className: "mt-1 text-sm text-muted-foreground", children: thread.summary }),
2035
+ /* @__PURE__ */ jsxs9("div", { className: "mt-2 flex flex-wrap gap-4 text-xs text-muted-foreground", children: [
2036
+ thread?.createdAt && /* @__PURE__ */ jsxs9("span", { children: [
2037
+ "Created ",
2038
+ formatDate3(thread.createdAt)
2039
+ ] }),
2040
+ thread?.updatedAt && /* @__PURE__ */ jsxs9("span", { children: [
2041
+ "Updated ",
2042
+ formatDate3(thread.updatedAt)
2043
+ ] }),
2044
+ thread?.participants && /* @__PURE__ */ jsxs9("span", { children: [
2045
+ thread.participants.length,
2046
+ " participants"
2047
+ ] })
2048
+ ] })
2049
+ ] })
2050
+ ] }),
2051
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-1", children: [
2052
+ /* @__PURE__ */ jsx14("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs9("h3", { className: "text-sm font-medium text-muted-foreground", children: [
2053
+ "Messages (",
2054
+ messages.length,
2055
+ pageInfo?.hasMoreBefore ? "+" : "",
2056
+ ")"
2057
+ ] }) }),
2058
+ pageInfo?.hasMoreBefore && /* @__PURE__ */ jsx14("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsxs9(
2059
+ Button,
2060
+ {
2061
+ variant: "ghost",
2062
+ size: "sm",
2063
+ onClick: () => void loadMore(),
2064
+ disabled: isLoadingMore,
2065
+ children: [
2066
+ isLoadingMore ? /* @__PURE__ */ jsx14(Loader2, { className: "mr-2 h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx14(ChevronUp2, { className: "mr-2 h-3 w-3" }),
2067
+ "Load older messages"
2068
+ ]
2069
+ }
2070
+ ) }),
2071
+ /* @__PURE__ */ jsx14("div", { className: "rounded-lg border bg-card", children: messages.length === 0 ? /* @__PURE__ */ jsx14("p", { className: "p-6 text-center text-sm text-muted-foreground", children: "No messages in this thread yet." }) : /* @__PURE__ */ jsx14("div", { className: "divide-y", children: messages.map((message) => /* @__PURE__ */ jsx14(MessageRow, { message }, message.id)) }) })
2072
+ ] })
2073
+ ] });
2074
+ };
2075
+ function MessageRow({ message }) {
2076
+ const [expanded, setExpanded] = useState4(false);
2077
+ const hasToolCalls = Array.isArray(message.toolCalls) && message.toolCalls.length > 0;
2078
+ const hasReasoning = !!message.reasoning;
2079
+ return /* @__PURE__ */ jsx14("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-3", children: [
2080
+ /* @__PURE__ */ jsx14(SenderIcon, { senderType: message.senderType }),
2081
+ /* @__PURE__ */ jsxs9("div", { className: "flex-1 min-w-0", children: [
2082
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 text-xs", children: [
2083
+ /* @__PURE__ */ jsx14("span", { className: "font-medium", children: message.senderId ?? message.senderUserId ?? message.senderType }),
2084
+ /* @__PURE__ */ jsx14(Badge, { variant: "outline", className: "text-[10px] px-1.5 py-0", children: message.senderType }),
2085
+ message.createdAt && /* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: formatTimestamp(message.createdAt) })
2086
+ ] }),
2087
+ message.content && /* @__PURE__ */ jsx14("p", { className: "mt-1 text-sm whitespace-pre-wrap break-words", children: message.content }),
2088
+ (hasToolCalls || hasReasoning) && /* @__PURE__ */ jsxs9("div", { className: "mt-2 space-y-2", children: [
2089
+ hasToolCalls && /* @__PURE__ */ jsxs9(
2090
+ "button",
2091
+ {
2092
+ type: "button",
2093
+ onClick: () => setExpanded(!expanded),
2094
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors",
2095
+ children: [
2096
+ /* @__PURE__ */ jsx14(Wrench, { className: "h-3 w-3" }),
2097
+ message.toolCalls.length,
2098
+ " tool call",
2099
+ message.toolCalls.length > 1 ? "s" : ""
2100
+ ]
2101
+ }
2102
+ ),
2103
+ hasReasoning && /* @__PURE__ */ jsxs9(
2104
+ "button",
2105
+ {
2106
+ type: "button",
2107
+ onClick: () => setExpanded(!expanded),
2108
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors",
2109
+ children: [
2110
+ /* @__PURE__ */ jsx14(Cpu, { className: "h-3 w-3" }),
2111
+ "Reasoning"
2112
+ ]
2113
+ }
2114
+ ),
2115
+ expanded && /* @__PURE__ */ jsx14("pre", { className: "mt-2 rounded-md bg-muted p-3 text-xs overflow-auto max-h-60", children: JSON.stringify(
2116
+ {
2117
+ ...hasToolCalls ? { toolCalls: message.toolCalls } : {},
2118
+ ...hasReasoning ? { reasoning: message.reasoning } : {}
2119
+ },
2120
+ null,
2121
+ 2
2122
+ ) })
2123
+ ] })
2124
+ ] })
2125
+ ] }) });
2126
+ }
2127
+ function SenderIcon({ senderType }) {
2128
+ const base = "flex h-7 w-7 shrink-0 items-center justify-center rounded-full";
2129
+ switch (senderType) {
2130
+ case "agent":
2131
+ return /* @__PURE__ */ jsx14("div", { className: cn(base, "bg-primary/10 text-primary"), children: /* @__PURE__ */ jsx14(Bot2, { className: "h-3.5 w-3.5" }) });
2132
+ case "user":
2133
+ return /* @__PURE__ */ jsx14("div", { className: cn(base, "bg-secondary text-secondary-foreground"), children: /* @__PURE__ */ jsx14(User, { className: "h-3.5 w-3.5" }) });
2134
+ case "tool":
2135
+ return /* @__PURE__ */ jsx14("div", { className: cn(base, "bg-muted text-muted-foreground"), children: /* @__PURE__ */ jsx14(Wrench, { className: "h-3.5 w-3.5" }) });
2136
+ default:
2137
+ return /* @__PURE__ */ jsx14("div", { className: cn(base, "bg-muted text-muted-foreground"), children: /* @__PURE__ */ jsx14(Cpu, { className: "h-3.5 w-3.5" }) });
2138
+ }
2139
+ }
2140
+ function formatDate3(value) {
2141
+ const date = new Date(value);
2142
+ if (Number.isNaN(date.getTime())) return value;
2143
+ return date.toLocaleDateString(void 0, {
2144
+ month: "short",
2145
+ day: "numeric",
2146
+ year: "numeric"
2147
+ });
2148
+ }
2149
+ function formatTimestamp(value) {
2150
+ const date = new Date(value);
2151
+ if (Number.isNaN(date.getTime())) return value;
2152
+ return date.toLocaleString(void 0, {
2153
+ month: "short",
2154
+ day: "numeric",
2155
+ hour: "numeric",
2156
+ minute: "2-digit",
2157
+ second: "2-digit"
2158
+ });
2159
+ }
2160
+
2161
+ // src/components/views/ParticipantsView.tsx
2162
+ import { Search as Search2, Users as Users2 } from "lucide-react";
2163
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2164
+ var ParticipantsView = ({
2165
+ config,
2166
+ participants,
2167
+ searchValue,
2168
+ onSearchChange,
2169
+ onParticipantClick
2170
+ }) => {
2171
+ return /* @__PURE__ */ jsxs10("div", { className: "space-y-4", children: [
2172
+ /* @__PURE__ */ jsxs10("div", { className: "relative max-w-sm", children: [
2173
+ /* @__PURE__ */ jsx15(Search2, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
2174
+ /* @__PURE__ */ jsx15(
2175
+ Input,
2176
+ {
2177
+ className: "pl-9",
2178
+ placeholder: config.labels.participantSearchPlaceholder,
2179
+ value: searchValue,
2180
+ onChange: (e) => onSearchChange(e.target.value)
2181
+ }
2182
+ )
2183
+ ] }),
2184
+ participants.length === 0 ? /* @__PURE__ */ jsxs10("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
2185
+ /* @__PURE__ */ jsx15(Users2, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
2186
+ /* @__PURE__ */ jsx15("p", { className: "mt-3 text-sm text-muted-foreground", children: searchValue ? config.labels.noResults : config.labels.emptyDescription })
2187
+ ] }) : /* @__PURE__ */ jsx15("div", { className: "space-y-2", children: participants.map((p) => /* @__PURE__ */ jsxs10(
2188
+ "div",
2189
+ {
2190
+ className: "flex items-center gap-4 rounded-lg border bg-card p-4 transition-colors hover:bg-muted/50 cursor-pointer",
2191
+ onClick: () => onParticipantClick?.(p.externalId),
2192
+ children: [
2193
+ /* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
2194
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
2195
+ /* @__PURE__ */ jsx15("p", { className: "font-medium truncate", children: p.displayName }),
2196
+ /* @__PURE__ */ jsx15(Badge, { variant: "outline", className: "shrink-0 text-xs", children: p.participantType }),
2197
+ /* @__PURE__ */ jsx15(Badge, { variant: p.isGlobal ? "default" : "secondary", className: "shrink-0 text-xs", children: p.isGlobal ? config.labels.scopeGlobal : config.labels.scopeScoped })
2198
+ ] }),
2199
+ /* @__PURE__ */ jsx15("p", { className: "mt-1 text-xs text-muted-foreground", children: p.externalId })
2200
+ ] }),
2201
+ /* @__PURE__ */ jsxs10("div", { className: "text-right text-xs text-muted-foreground shrink-0 space-y-1", children: [
2202
+ /* @__PURE__ */ jsxs10("p", { children: [
2203
+ formatNumber3(p.messageCount),
2204
+ " messages"
2205
+ ] }),
2206
+ /* @__PURE__ */ jsxs10("p", { children: [
2207
+ formatNumber3(p.threadCount),
2208
+ " threads"
2209
+ ] }),
2210
+ /* @__PURE__ */ jsx15("p", { children: formatDate4(p.lastActivityAt) })
2211
+ ] })
2212
+ ]
2213
+ },
2214
+ `${p.namespace}:${p.externalId}`
2215
+ )) })
2216
+ ] });
2217
+ };
2218
+ function formatDate4(value) {
2219
+ if (!value) return "No activity";
2220
+ const date = new Date(value);
2221
+ if (Number.isNaN(date.getTime())) return value;
2222
+ return date.toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
2223
+ }
2224
+ function formatNumber3(value) {
2225
+ return new Intl.NumberFormat().format(value);
2226
+ }
2227
+
2228
+ // src/components/views/ParticipantDetailView.tsx
2229
+ import { useCallback as useCallback4, useEffect as useEffect6, useState as useState5 } from "react";
2230
+ import { ArrowLeft as ArrowLeft2, Loader2 as Loader22, Save } from "lucide-react";
2231
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
2232
+ var ParticipantDetailView = ({
2233
+ participantId,
2234
+ config,
2235
+ onBack
2236
+ }) => {
2237
+ const [data, setData] = useState5(null);
2238
+ const [editJson, setEditJson] = useState5("");
2239
+ const [isLoading, setIsLoading] = useState5(true);
2240
+ const [isSaving, setIsSaving] = useState5(false);
2241
+ const [error, setError] = useState5(null);
2242
+ const [saveMessage, setSaveMessage] = useState5(null);
2243
+ const fetchOptions = {
2244
+ baseUrl: config.baseUrl,
2245
+ getRequestHeaders: config.getRequestHeaders
2246
+ };
2247
+ const load = useCallback4(async () => {
2248
+ setIsLoading(true);
2249
+ setError(null);
2250
+ try {
2251
+ const result = await fetchParticipantDetail(participantId, fetchOptions);
2252
+ setData(result);
2253
+ setEditJson(JSON.stringify(result, null, 2));
2254
+ } catch (err) {
2255
+ setError(err instanceof Error ? err.message : "Failed to load participant");
2256
+ } finally {
2257
+ setIsLoading(false);
2258
+ }
2259
+ }, [participantId, config.baseUrl, config.getRequestHeaders]);
2260
+ useEffect6(() => {
2261
+ void load();
2262
+ }, [load]);
2263
+ const handleSave = async () => {
2264
+ setIsSaving(true);
2265
+ setError(null);
2266
+ setSaveMessage(null);
2267
+ try {
2268
+ const parsed = JSON.parse(editJson);
2269
+ const updated = await updateParticipant(participantId, parsed, fetchOptions);
2270
+ setData(updated);
2271
+ setEditJson(JSON.stringify(updated, null, 2));
2272
+ setSaveMessage("Saved successfully");
2273
+ setTimeout(() => setSaveMessage(null), 3e3);
2274
+ } catch (err) {
2275
+ setError(err instanceof Error ? err.message : "Failed to save");
2276
+ } finally {
2277
+ setIsSaving(false);
2278
+ }
2279
+ };
2280
+ if (isLoading) {
2281
+ return /* @__PURE__ */ jsx16("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx16(Loader22, { className: "h-6 w-6 animate-spin text-muted-foreground" }) });
2282
+ }
2283
+ return /* @__PURE__ */ jsxs11("div", { className: "space-y-6", children: [
2284
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-4", children: [
2285
+ /* @__PURE__ */ jsx16(Button, { variant: "ghost", size: "icon", onClick: onBack, children: /* @__PURE__ */ jsx16(ArrowLeft2, { className: "h-4 w-4" }) }),
2286
+ /* @__PURE__ */ jsxs11("div", { className: "flex-1 min-w-0", children: [
2287
+ /* @__PURE__ */ jsx16("h2", { className: "text-xl font-semibold truncate", children: participantId }),
2288
+ /* @__PURE__ */ jsx16("p", { className: "text-sm text-muted-foreground", children: "Participant Detail" })
2289
+ ] }),
2290
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
2291
+ saveMessage && /* @__PURE__ */ jsx16("span", { className: "text-xs text-emerald-600", children: saveMessage }),
2292
+ /* @__PURE__ */ jsxs11(Button, { size: "sm", onClick: () => void handleSave(), disabled: isSaving, children: [
2293
+ isSaving ? /* @__PURE__ */ jsx16(Loader22, { className: "mr-2 h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx16(Save, { className: "mr-2 h-3 w-3" }),
2294
+ "Save"
2295
+ ] })
2296
+ ] })
2297
+ ] }),
2298
+ error && /* @__PURE__ */ jsx16("div", { className: "rounded-lg border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
2299
+ /* @__PURE__ */ jsx16("div", { className: "rounded-lg border bg-card", children: /* @__PURE__ */ jsx16(
2300
+ "textarea",
2301
+ {
2302
+ className: "w-full min-h-[400px] p-4 font-mono text-sm bg-transparent resize-y focus:outline-none",
2303
+ value: editJson,
2304
+ onChange: (e) => setEditJson(e.target.value),
2305
+ spellCheck: false
2306
+ }
2307
+ ) })
2308
+ ] });
2309
+ };
2310
+
2311
+ // src/components/views/AgentsView.tsx
2312
+ import { Search as Search3, Bot as Bot3 } from "lucide-react";
2313
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
2314
+ var AgentsView = ({
2315
+ config,
2316
+ agents,
2317
+ searchValue,
2318
+ onSearchChange,
2319
+ onAgentClick
2320
+ }) => {
2321
+ return /* @__PURE__ */ jsxs12("div", { className: "space-y-4", children: [
2322
+ /* @__PURE__ */ jsxs12("div", { className: "relative max-w-sm", children: [
2323
+ /* @__PURE__ */ jsx17(Search3, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
2324
+ /* @__PURE__ */ jsx17(
2325
+ Input,
2326
+ {
2327
+ className: "pl-9",
2328
+ placeholder: config.labels.agentSearchPlaceholder,
2329
+ value: searchValue,
2330
+ onChange: (e) => onSearchChange(e.target.value)
2331
+ }
2332
+ )
2333
+ ] }),
2334
+ agents.length === 0 ? /* @__PURE__ */ jsxs12("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
2335
+ /* @__PURE__ */ jsx17(Bot3, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
2336
+ /* @__PURE__ */ jsx17("p", { className: "mt-3 text-sm text-muted-foreground", children: searchValue ? config.labels.noResults : config.labels.emptyDescription })
2337
+ ] }) : /* @__PURE__ */ jsx17("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: agents.map((agent) => /* @__PURE__ */ jsxs12(
2338
+ "div",
2339
+ {
2340
+ className: "rounded-lg border bg-card p-5 transition-colors hover:bg-muted/50 cursor-pointer",
2341
+ onClick: () => onAgentClick?.(agent.agentId),
2342
+ children: [
2343
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-start justify-between gap-3", children: [
2344
+ /* @__PURE__ */ jsxs12("div", { className: "min-w-0", children: [
2345
+ /* @__PURE__ */ jsx17("p", { className: "font-medium truncate", children: agent.displayName }),
2346
+ /* @__PURE__ */ jsx17("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: agent.description ?? agent.agentId })
2347
+ ] }),
2348
+ /* @__PURE__ */ jsx17(Badge, { variant: "outline", className: "shrink-0", children: agent.isConfigured ? config.labels.configured : config.labels.unconfigured })
2349
+ ] }),
2350
+ /* @__PURE__ */ jsxs12("div", { className: "mt-4 grid grid-cols-2 gap-2 text-xs text-muted-foreground", children: [
2351
+ /* @__PURE__ */ jsxs12("span", { children: [
2352
+ formatNumber4(agent.messageCount),
2353
+ " messages"
2354
+ ] }),
2355
+ /* @__PURE__ */ jsxs12("span", { children: [
2356
+ formatNumber4(agent.llmCallCount),
2357
+ " LLM calls"
2358
+ ] }),
2359
+ /* @__PURE__ */ jsxs12("span", { children: [
2360
+ formatNumber4(agent.toolCallMessageCount),
2361
+ " tool calls"
2362
+ ] }),
2363
+ /* @__PURE__ */ jsxs12("span", { children: [
2364
+ formatNumber4(agent.totalTokens),
2365
+ " tokens"
2366
+ ] })
2367
+ ] }),
2368
+ /* @__PURE__ */ jsx17("p", { className: "mt-3 text-xs text-muted-foreground", children: formatDate5(agent.lastActivityAt) })
2369
+ ]
2370
+ },
2371
+ `${agent.namespace}:${agent.agentId}`
2372
+ )) })
2373
+ ] });
2374
+ };
2375
+ function formatDate5(value) {
2376
+ if (!value) return "No activity";
2377
+ const date = new Date(value);
2378
+ if (Number.isNaN(date.getTime())) return value;
2379
+ return date.toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
2380
+ }
2381
+ function formatNumber4(value) {
2382
+ return new Intl.NumberFormat().format(value);
2383
+ }
2384
+
2385
+ // src/components/views/AgentDetailView.tsx
2386
+ import { ArrowLeft as ArrowLeft3, Bot as Bot4 } from "lucide-react";
2387
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
2388
+ var AgentDetailView = ({
2389
+ agentId,
2390
+ config,
2391
+ agents,
2392
+ onBack
2393
+ }) => {
2394
+ const agent = agents.find((a) => a.agentId === agentId);
2395
+ if (!agent) {
2396
+ return /* @__PURE__ */ jsxs13("div", { className: "space-y-4 py-10 text-center", children: [
2397
+ /* @__PURE__ */ jsxs13("p", { className: "text-muted-foreground", children: [
2398
+ "Agent not found: ",
2399
+ agentId
2400
+ ] }),
2401
+ /* @__PURE__ */ jsxs13(Button, { variant: "outline", onClick: onBack, children: [
2402
+ /* @__PURE__ */ jsx18(ArrowLeft3, { className: "mr-2 h-4 w-4" }),
2403
+ " Back"
2404
+ ] })
2405
+ ] });
2406
+ }
2407
+ const stats = [
2408
+ { label: "Messages", value: agent.messageCount },
2409
+ { label: "LLM Calls", value: agent.llmCallCount },
2410
+ { label: "Tool Calls", value: agent.toolCallMessageCount },
2411
+ { label: "Input Tokens", value: agent.inputTokens },
2412
+ { label: "Output Tokens", value: agent.outputTokens },
2413
+ { label: "Reasoning Tokens", value: agent.reasoningTokens },
2414
+ { label: "Cache Read", value: agent.cacheReadInputTokens },
2415
+ { label: "Cache Created", value: agent.cacheCreationInputTokens },
2416
+ { label: "Total Tokens", value: agent.totalTokens }
2417
+ ];
2418
+ return /* @__PURE__ */ jsxs13("div", { className: "space-y-6", children: [
2419
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-start gap-4", children: [
2420
+ /* @__PURE__ */ jsx18(Button, { variant: "ghost", size: "icon", className: "mt-1 shrink-0", onClick: onBack, children: /* @__PURE__ */ jsx18(ArrowLeft3, { className: "h-4 w-4" }) }),
2421
+ /* @__PURE__ */ jsxs13("div", { className: "flex-1 min-w-0", children: [
2422
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3", children: [
2423
+ /* @__PURE__ */ jsx18("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx18(Bot4, { className: "h-5 w-5" }) }),
2424
+ /* @__PURE__ */ jsxs13("div", { children: [
2425
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
2426
+ /* @__PURE__ */ jsx18("h2", { className: "text-xl font-semibold", children: agent.displayName }),
2427
+ /* @__PURE__ */ jsx18(Badge, { variant: "outline", children: agent.isConfigured ? config.labels.configured : config.labels.unconfigured })
2428
+ ] }),
2429
+ agent.description && /* @__PURE__ */ jsx18("p", { className: "text-sm text-muted-foreground", children: agent.description })
2430
+ ] })
2431
+ ] }),
2432
+ /* @__PURE__ */ jsxs13("div", { className: "mt-2 flex flex-wrap gap-4 text-xs text-muted-foreground", children: [
2433
+ /* @__PURE__ */ jsxs13("span", { children: [
2434
+ "ID: ",
2435
+ agent.agentId
2436
+ ] }),
2437
+ /* @__PURE__ */ jsxs13("span", { children: [
2438
+ "Namespace: ",
2439
+ agent.namespace
2440
+ ] }),
2441
+ agent.lastActivityAt && /* @__PURE__ */ jsxs13("span", { children: [
2442
+ "Last active: ",
2443
+ formatDate6(agent.lastActivityAt)
2444
+ ] })
2445
+ ] })
2446
+ ] })
2447
+ ] }),
2448
+ /* @__PURE__ */ jsx18("div", { className: "grid gap-4 sm:grid-cols-3 lg:grid-cols-3", children: stats.map((stat) => /* @__PURE__ */ jsxs13("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [
2449
+ /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-muted-foreground", children: stat.label }),
2450
+ /* @__PURE__ */ jsx18("p", { className: "mt-2 text-2xl font-semibold tracking-tight", children: new Intl.NumberFormat().format(stat.value) })
2451
+ ] }, stat.label)) })
2452
+ ] });
2453
+ };
2454
+ function formatDate6(value) {
2455
+ const date = new Date(value);
2456
+ if (Number.isNaN(date.getTime())) return value;
2457
+ return date.toLocaleString(void 0, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
2458
+ }
2459
+
2460
+ // src/components/views/CollectionItemsView.tsx
2461
+ import { useCallback as useCallback5, useEffect as useEffect7, useState as useState6 } from "react";
2462
+ import { Loader2 as Loader23, Plus, Search as Search4, Database as Database2 } from "lucide-react";
2463
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
2464
+ var CollectionItemsView = ({
2465
+ collection,
2466
+ config,
2467
+ namespace,
2468
+ onItemClick,
2469
+ onCreateNew
2470
+ }) => {
2471
+ const [items, setItems] = useState6([]);
2472
+ const [isLoading, setIsLoading] = useState6(true);
2473
+ const [search, setSearch] = useState6("");
2474
+ const [error, setError] = useState6(null);
2475
+ const fetchOptions = {
2476
+ baseUrl: config.baseUrl,
2477
+ getRequestHeaders: config.getRequestHeaders
2478
+ };
2479
+ const load = useCallback5(async () => {
2480
+ setIsLoading(true);
2481
+ setError(null);
2482
+ try {
2483
+ const result = await fetchCollectionItems(
2484
+ collection,
2485
+ { search: search || void 0, namespace, limit: 50 },
2486
+ fetchOptions
2487
+ );
2488
+ setItems(result);
2489
+ } catch (err) {
2490
+ setError(err instanceof Error ? err.message : "Failed to load items");
2491
+ } finally {
2492
+ setIsLoading(false);
2493
+ }
2494
+ }, [collection, search, namespace, config.baseUrl, config.getRequestHeaders]);
2495
+ useEffect7(() => {
2496
+ void load();
2497
+ }, [load]);
2498
+ const getItemId = (item) => {
2499
+ return String(item.id ?? item._id ?? JSON.stringify(item).slice(0, 40));
2500
+ };
2501
+ const getItemPreview = (item) => {
2502
+ const { id, _id, ...rest } = item;
2503
+ const name = item.name ?? item.title ?? item.displayName ?? item.label;
2504
+ if (typeof name === "string") return name;
2505
+ const keys = Object.keys(rest);
2506
+ if (keys.length === 0) return "(empty)";
2507
+ return keys.slice(0, 3).map((k) => `${k}: ${JSON.stringify(rest[k])?.slice(0, 30)}`).join(", ");
2508
+ };
2509
+ return /* @__PURE__ */ jsxs14("div", { className: "space-y-4", children: [
2510
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between gap-4", children: [
2511
+ /* @__PURE__ */ jsx19("h2", { className: "text-lg font-semibold capitalize", children: collection }),
2512
+ onCreateNew && /* @__PURE__ */ jsxs14(Button, { size: "sm", onClick: onCreateNew, children: [
2513
+ /* @__PURE__ */ jsx19(Plus, { className: "mr-2 h-3 w-3" }),
2514
+ " New"
2515
+ ] })
2516
+ ] }),
2517
+ /* @__PURE__ */ jsxs14("div", { className: "relative max-w-sm", children: [
2518
+ /* @__PURE__ */ jsx19(Search4, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
2519
+ /* @__PURE__ */ jsx19(
2520
+ Input,
2521
+ {
2522
+ className: "pl-9",
2523
+ placeholder: `Search ${collection}...`,
2524
+ value: search,
2525
+ onChange: (e) => setSearch(e.target.value)
2526
+ }
2527
+ )
2528
+ ] }),
2529
+ error && /* @__PURE__ */ jsx19("div", { className: "rounded-lg border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
2530
+ isLoading ? /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx19(Loader23, { className: "h-6 w-6 animate-spin text-muted-foreground" }) }) : items.length === 0 ? /* @__PURE__ */ jsxs14("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
2531
+ /* @__PURE__ */ jsx19(Database2, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
2532
+ /* @__PURE__ */ jsx19("p", { className: "mt-3 text-sm text-muted-foreground", children: search ? config.labels.noResults : `No items in ${collection}` })
2533
+ ] }) : /* @__PURE__ */ jsx19("div", { className: "space-y-2", children: items.map((item, idx) => {
2534
+ const itemId = getItemId(item);
2535
+ return /* @__PURE__ */ jsx19(
2536
+ "div",
2537
+ {
2538
+ className: "flex items-center gap-4 rounded-lg border bg-card p-4 transition-colors hover:bg-muted/50 cursor-pointer",
2539
+ onClick: () => onItemClick?.(itemId),
2540
+ children: /* @__PURE__ */ jsxs14("div", { className: "flex-1 min-w-0", children: [
2541
+ /* @__PURE__ */ jsx19("p", { className: "font-medium font-mono text-sm truncate", children: itemId }),
2542
+ /* @__PURE__ */ jsx19("p", { className: "mt-1 text-xs text-muted-foreground truncate", children: getItemPreview(item) })
2543
+ ] })
2544
+ },
2545
+ itemId + idx
2546
+ );
2547
+ }) })
2548
+ ] });
2549
+ };
2550
+
2551
+ // src/components/views/CollectionItemDetailView.tsx
2552
+ import { useCallback as useCallback6, useEffect as useEffect8, useState as useState7 } from "react";
2553
+ import { ArrowLeft as ArrowLeft5, Loader2 as Loader24, Save as Save2, Trash2 } from "lucide-react";
2554
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
2555
+ var CollectionItemDetailView = ({
2556
+ collection,
2557
+ itemId,
2558
+ config,
2559
+ namespace,
2560
+ onBack,
2561
+ onDeleted
2562
+ }) => {
2563
+ const isNew = !itemId;
2564
+ const [editJson, setEditJson] = useState7(isNew ? "{\n \n}" : "");
2565
+ const [isLoading, setIsLoading] = useState7(!isNew);
2566
+ const [isSaving, setIsSaving] = useState7(false);
2567
+ const [isDeleting, setIsDeleting] = useState7(false);
2568
+ const [error, setError] = useState7(null);
2569
+ const [saveMessage, setSaveMessage] = useState7(null);
2570
+ const fetchOptions = {
2571
+ baseUrl: config.baseUrl,
2572
+ getRequestHeaders: config.getRequestHeaders
2573
+ };
2574
+ const load = useCallback6(async () => {
2575
+ if (!itemId) return;
2576
+ setIsLoading(true);
2577
+ setError(null);
2578
+ try {
2579
+ const result = await fetchCollectionItem(collection, itemId, namespace, fetchOptions);
2580
+ setEditJson(JSON.stringify(result, null, 2));
2581
+ } catch (err) {
2582
+ setError(err instanceof Error ? err.message : "Failed to load item");
2583
+ } finally {
2584
+ setIsLoading(false);
2585
+ }
2586
+ }, [collection, itemId, namespace, config.baseUrl, config.getRequestHeaders]);
2587
+ useEffect8(() => {
2588
+ void load();
2589
+ }, [load]);
2590
+ const handleSave = async () => {
2591
+ setIsSaving(true);
2592
+ setError(null);
2593
+ setSaveMessage(null);
2594
+ try {
2595
+ const parsed = JSON.parse(editJson);
2596
+ if (isNew) {
2597
+ const created = await createCollectionItem(collection, parsed, namespace, fetchOptions);
2598
+ setEditJson(JSON.stringify(created, null, 2));
2599
+ setSaveMessage("Created successfully");
2600
+ } else {
2601
+ const updated = await updateCollectionItem(collection, itemId, parsed, namespace, fetchOptions);
2602
+ setEditJson(JSON.stringify(updated, null, 2));
2603
+ setSaveMessage("Saved successfully");
2604
+ }
2605
+ setTimeout(() => setSaveMessage(null), 3e3);
2606
+ } catch (err) {
2607
+ setError(err instanceof Error ? err.message : "Failed to save");
2608
+ } finally {
2609
+ setIsSaving(false);
2610
+ }
2611
+ };
2612
+ const handleDelete = async () => {
2613
+ if (!itemId) return;
2614
+ if (!window.confirm(`Delete this item from ${collection}?`)) return;
2615
+ setIsDeleting(true);
2616
+ setError(null);
2617
+ try {
2618
+ await deleteCollectionItem(collection, itemId, namespace, fetchOptions);
2619
+ onDeleted?.();
2620
+ onBack();
2621
+ } catch (err) {
2622
+ setError(err instanceof Error ? err.message : "Failed to delete");
2623
+ } finally {
2624
+ setIsDeleting(false);
2625
+ }
2626
+ };
2627
+ if (isLoading) {
2628
+ return /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx20(Loader24, { className: "h-6 w-6 animate-spin text-muted-foreground" }) });
2629
+ }
2630
+ return /* @__PURE__ */ jsxs15("div", { className: "space-y-6", children: [
2631
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-4", children: [
2632
+ /* @__PURE__ */ jsx20(Button, { variant: "ghost", size: "icon", onClick: onBack, children: /* @__PURE__ */ jsx20(ArrowLeft5, { className: "h-4 w-4" }) }),
2633
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx20("h2", { className: "text-xl font-semibold truncate capitalize", children: isNew ? `New ${collection} item` : `${collection} / ${itemId}` }) }),
2634
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
2635
+ saveMessage && /* @__PURE__ */ jsx20("span", { className: "text-xs text-emerald-600", children: saveMessage }),
2636
+ !isNew && /* @__PURE__ */ jsxs15(
2637
+ Button,
2638
+ {
2639
+ variant: "destructive",
2640
+ size: "sm",
2641
+ onClick: () => void handleDelete(),
2642
+ disabled: isDeleting,
2643
+ children: [
2644
+ isDeleting ? /* @__PURE__ */ jsx20(Loader24, { className: "mr-2 h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx20(Trash2, { className: "mr-2 h-3 w-3" }),
2645
+ "Delete"
2646
+ ]
2647
+ }
2648
+ ),
2649
+ /* @__PURE__ */ jsxs15(Button, { size: "sm", onClick: () => void handleSave(), disabled: isSaving, children: [
2650
+ isSaving ? /* @__PURE__ */ jsx20(Loader24, { className: "mr-2 h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx20(Save2, { className: "mr-2 h-3 w-3" }),
2651
+ isNew ? "Create" : "Save"
2652
+ ] })
2653
+ ] })
2654
+ ] }),
2655
+ error && /* @__PURE__ */ jsx20("div", { className: "rounded-lg border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
2656
+ /* @__PURE__ */ jsx20("div", { className: "rounded-lg border bg-card", children: /* @__PURE__ */ jsx20(
2657
+ "textarea",
2658
+ {
2659
+ className: "w-full min-h-[400px] p-4 font-mono text-sm bg-transparent resize-y focus:outline-none",
2660
+ value: editJson,
2661
+ onChange: (e) => setEditJson(e.target.value),
2662
+ spellCheck: false
2663
+ }
2664
+ ) })
2665
+ ] });
2666
+ };
2667
+
2668
+ // src/components/views/EventsView.tsx
2669
+ import { useCallback as useCallback7, useState as useState8 } from "react";
2670
+ import { Activity as Activity2, Loader2 as Loader25, Search as Search5 } from "lucide-react";
2671
+ import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
2672
+ var STATUS_VARIANTS = {
2673
+ pending: "outline",
2674
+ processing: "default",
2675
+ completed: "secondary",
2676
+ failed: "destructive",
2677
+ expired: "secondary",
2678
+ overwritten: "secondary"
2679
+ };
2680
+ var EventsView = ({ config }) => {
2681
+ const [threadId, setThreadId] = useState8("");
2682
+ const [event, setEvent] = useState8(null);
2683
+ const [hasSearched, setHasSearched] = useState8(false);
2684
+ const [isLoading, setIsLoading] = useState8(false);
2685
+ const [error, setError] = useState8(null);
2686
+ const fetchOptions = {
2687
+ baseUrl: config.baseUrl,
2688
+ getRequestHeaders: config.getRequestHeaders
2689
+ };
2690
+ const handleSearch = useCallback7(async () => {
2691
+ if (!threadId.trim()) return;
2692
+ setIsLoading(true);
2693
+ setError(null);
2694
+ setHasSearched(true);
2695
+ try {
2696
+ const result = await fetchThreadEvents(threadId.trim(), fetchOptions);
2697
+ setEvent(result ?? null);
2698
+ } catch (err) {
2699
+ setError(err instanceof Error ? err.message : "Failed to load events");
2700
+ } finally {
2701
+ setIsLoading(false);
2702
+ }
2703
+ }, [threadId, config.baseUrl, config.getRequestHeaders]);
2704
+ return /* @__PURE__ */ jsxs16("div", { className: "space-y-6", children: [
2705
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-end gap-3 max-w-lg", children: [
2706
+ /* @__PURE__ */ jsxs16("div", { className: "flex-1", children: [
2707
+ /* @__PURE__ */ jsx21("label", { className: "text-sm font-medium mb-1 block", children: "Thread ID" }),
2708
+ /* @__PURE__ */ jsxs16("div", { className: "relative", children: [
2709
+ /* @__PURE__ */ jsx21(Search5, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
2710
+ /* @__PURE__ */ jsx21(
2711
+ Input,
2712
+ {
2713
+ className: "pl-9",
2714
+ placeholder: "Enter thread ID to inspect events...",
2715
+ value: threadId,
2716
+ onChange: (e) => setThreadId(e.target.value),
2717
+ onKeyDown: (e) => e.key === "Enter" && void handleSearch()
2718
+ }
2719
+ )
2720
+ ] })
2721
+ ] }),
2722
+ /* @__PURE__ */ jsxs16(Button, { onClick: () => void handleSearch(), disabled: isLoading || !threadId.trim(), children: [
2723
+ isLoading ? /* @__PURE__ */ jsx21(Loader25, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
2724
+ "Inspect"
2725
+ ] })
2726
+ ] }),
2727
+ error && /* @__PURE__ */ jsx21("div", { className: "rounded-lg border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
2728
+ !hasSearched ? /* @__PURE__ */ jsxs16("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
2729
+ /* @__PURE__ */ jsx21(Activity2, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
2730
+ /* @__PURE__ */ jsx21("p", { className: "mt-3 text-sm text-muted-foreground", children: "Enter a thread ID to inspect its next pending queue event." })
2731
+ ] }) : isLoading ? /* @__PURE__ */ jsx21("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsx21(Loader25, { className: "h-6 w-6 animate-spin text-muted-foreground" }) }) : !event ? /* @__PURE__ */ jsxs16("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
2732
+ /* @__PURE__ */ jsx21(Activity2, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
2733
+ /* @__PURE__ */ jsx21("p", { className: "mt-3 text-sm text-muted-foreground", children: "No pending events found for this thread." })
2734
+ ] }) : /* @__PURE__ */ jsxs16("div", { className: "rounded-lg border bg-card p-5 space-y-4", children: [
2735
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-start justify-between gap-3", children: [
2736
+ /* @__PURE__ */ jsxs16("div", { children: [
2737
+ /* @__PURE__ */ jsx21("p", { className: "font-medium", children: event.eventType }),
2738
+ /* @__PURE__ */ jsx21("p", { className: "text-xs text-muted-foreground font-mono mt-1", children: event.id })
2739
+ ] }),
2740
+ /* @__PURE__ */ jsx21(Badge, { variant: STATUS_VARIANTS[event.status] ?? "outline", children: event.status })
2741
+ ] }),
2742
+ /* @__PURE__ */ jsxs16("div", { className: "grid gap-3 sm:grid-cols-2 text-sm", children: [
2743
+ event.traceId && /* @__PURE__ */ jsxs16("div", { children: [
2744
+ /* @__PURE__ */ jsx21("span", { className: "text-muted-foreground", children: "Trace:" }),
2745
+ " ",
2746
+ /* @__PURE__ */ jsx21("span", { className: "font-mono text-xs", children: event.traceId })
2747
+ ] }),
2748
+ event.parentEventId && /* @__PURE__ */ jsxs16("div", { children: [
2749
+ /* @__PURE__ */ jsx21("span", { className: "text-muted-foreground", children: "Parent:" }),
2750
+ " ",
2751
+ /* @__PURE__ */ jsx21("span", { className: "font-mono text-xs", children: event.parentEventId })
2752
+ ] }),
2753
+ event.priority != null && /* @__PURE__ */ jsxs16("div", { children: [
2754
+ /* @__PURE__ */ jsx21("span", { className: "text-muted-foreground", children: "Priority:" }),
2755
+ " ",
2756
+ event.priority
2757
+ ] }),
2758
+ event.createdAt && /* @__PURE__ */ jsxs16("div", { children: [
2759
+ /* @__PURE__ */ jsx21("span", { className: "text-muted-foreground", children: "Created:" }),
2760
+ " ",
2761
+ formatTimestamp2(event.createdAt)
2762
+ ] })
2763
+ ] }),
2764
+ event.payload != null && /* @__PURE__ */ jsxs16("div", { children: [
2765
+ /* @__PURE__ */ jsx21("p", { className: "text-xs font-medium text-muted-foreground mb-1", children: "Payload" }),
2766
+ /* @__PURE__ */ jsx21("pre", { className: "rounded-md bg-muted p-3 text-xs overflow-auto max-h-60", children: JSON.stringify(event.payload, null, 2) })
2767
+ ] }),
2768
+ event.metadata != null && Object.keys(event.metadata).length > 0 && /* @__PURE__ */ jsxs16("div", { children: [
2769
+ /* @__PURE__ */ jsx21("p", { className: "text-xs font-medium text-muted-foreground mb-1", children: "Metadata" }),
2770
+ /* @__PURE__ */ jsx21("pre", { className: "rounded-md bg-muted p-3 text-xs overflow-auto max-h-40", children: JSON.stringify(event.metadata, null, 2) })
2771
+ ] })
2772
+ ] })
2773
+ ] });
2774
+ };
2775
+ function formatTimestamp2(value) {
2776
+ const date = new Date(value);
2777
+ if (Number.isNaN(date.getTime())) return value;
2778
+ return date.toLocaleString(void 0, {
2779
+ month: "short",
2780
+ day: "numeric",
2781
+ hour: "numeric",
2782
+ minute: "2-digit",
2783
+ second: "2-digit"
2784
+ });
2785
+ }
2786
+
2787
+ // src/CopilotzAdmin.tsx
2788
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
2789
+ var CopilotzAdmin = ({
2790
+ config: userConfig,
2791
+ className
2792
+ }) => {
2793
+ const config = useMemo3(
2794
+ () => mergeAdminConfig(defaultAdminConfig, userConfig),
2795
+ [userConfig]
2796
+ );
2797
+ const [route, setRoute] = useState9({ page: config.defaultPage });
2798
+ const [namespace, setNamespace] = useState9(config.namespace);
2799
+ const [collections, setCollections] = useState9([]);
2800
+ const [threadSearch, setThreadSearch] = useState9("");
2801
+ const [participantSearch, setParticipantSearch] = useState9("");
2802
+ const [agentSearch, setAgentSearch] = useState9("");
2803
+ const deferredThreadSearch = useDeferredValue(threadSearch);
2804
+ const deferredParticipantSearch = useDeferredValue(participantSearch);
2805
+ const deferredAgentSearch = useDeferredValue(agentSearch);
2806
+ const admin = useCopilotzAdmin({
2807
+ baseUrl: config.baseUrl,
2808
+ getRequestHeaders: config.getRequestHeaders,
2809
+ namespace,
2810
+ range: config.initialRange,
2811
+ interval: config.initialInterval,
2812
+ threadSearch: deferredThreadSearch,
2813
+ participantSearch: deferredParticipantSearch,
2814
+ agentSearch: deferredAgentSearch
2815
+ });
2816
+ useEffect9(() => {
2817
+ if (!config.features.showCollections) return;
2818
+ fetchCollectionNames({
2819
+ baseUrl: config.baseUrl,
2820
+ getRequestHeaders: config.getRequestHeaders
2821
+ }).then(setCollections).catch(() => setCollections([]));
2822
+ }, [config.baseUrl, config.getRequestHeaders, config.features.showCollections]);
2823
+ const navigate = useCallback8(
2824
+ (next) => {
2825
+ setRoute(next);
2826
+ config.onNavigate?.(next);
2827
+ },
2828
+ [config]
2829
+ );
2830
+ const handleSidebarNavigate = useCallback8(
2831
+ (page) => navigate({ page }),
2832
+ [navigate]
2833
+ );
2834
+ const handleSidebarRouteNavigate = useCallback8(
2835
+ (r) => navigate(r),
2836
+ [navigate]
2837
+ );
2838
+ const handleThreadClick = useCallback8(
2839
+ (threadId) => navigate({ page: "thread-detail", resourceId: threadId }),
2840
+ [navigate]
2841
+ );
2842
+ const handleBackToThreads = useCallback8(() => navigate({ page: "threads" }), [navigate]);
2843
+ const handleParticipantClick = useCallback8(
2844
+ (id) => navigate({ page: "participant-detail", resourceId: id }),
2845
+ [navigate]
2846
+ );
2847
+ const handleBackToParticipants = useCallback8(() => navigate({ page: "participants" }), [navigate]);
2848
+ const handleAgentClick = useCallback8(
2849
+ (id) => navigate({ page: "agent-detail", resourceId: id }),
2850
+ [navigate]
2851
+ );
2852
+ const handleBackToAgents = useCallback8(() => navigate({ page: "agents" }), [navigate]);
2853
+ const handleCollectionItemClick = useCallback8(
2854
+ (itemId) => navigate({ page: "collection-item-detail", resourceId: itemId, collection: route.collection }),
2855
+ [navigate, route.collection]
2856
+ );
2857
+ const handleCollectionCreateNew = useCallback8(
2858
+ () => navigate({ page: "collection-item-detail", resourceId: void 0, collection: route.collection }),
2859
+ [navigate, route.collection]
2860
+ );
2861
+ const handleBackToCollectionItems = useCallback8(
2862
+ () => navigate({ page: "collection-items", collection: route.collection }),
2863
+ [navigate, route.collection]
2864
+ );
2865
+ const sidebarPage = (() => {
2866
+ switch (route.page) {
2867
+ case "thread-detail":
2868
+ return "threads";
2869
+ case "participant-detail":
2870
+ return "participants";
2871
+ case "agent-detail":
2872
+ return "agents";
2873
+ case "collection-item-detail":
2874
+ return "collection-items";
2875
+ default:
2876
+ return route.page;
2877
+ }
2878
+ })();
2879
+ if (admin.isLoading && !admin.overview) {
2880
+ return /* @__PURE__ */ jsx22(Card, { className: cn("border-border", className), children: /* @__PURE__ */ jsx22(CardContent, { className: "text-muted-foreground flex items-center justify-center min-h-[200px]", children: config.labels.loading }) });
2881
+ }
2882
+ if (admin.error && !admin.overview) {
2883
+ return /* @__PURE__ */ jsx22(Card, { className: cn("border-destructive/50 bg-destructive/10", className), children: /* @__PURE__ */ jsxs17(CardContent, { className: "space-y-4", children: [
2884
+ /* @__PURE__ */ jsx22("p", { className: "text-base font-semibold text-destructive", children: admin.error.message }),
2885
+ /* @__PURE__ */ jsx22(Button, { variant: "destructive", onClick: () => void admin.refresh(), children: config.labels.retry })
2886
+ ] }) });
2887
+ }
2888
+ const renderCurrentView = () => {
2889
+ switch (route.page) {
2890
+ case "dashboard":
2891
+ return /* @__PURE__ */ jsx22(
2892
+ DashboardView,
2893
+ {
2894
+ config,
2895
+ overview: admin.overview,
2896
+ activity: admin.activity,
2897
+ threads: admin.threads,
2898
+ participants: admin.participants,
2899
+ agents: admin.agents,
2900
+ interval: admin.filters.interval,
2901
+ threadSearch,
2902
+ participantSearch,
2903
+ agentSearch,
2904
+ onThreadSearchChange: setThreadSearch,
2905
+ onParticipantSearchChange: setParticipantSearch,
2906
+ onAgentSearchChange: setAgentSearch,
2907
+ onThreadClick: handleThreadClick
2908
+ }
2909
+ );
2910
+ case "threads":
2911
+ return /* @__PURE__ */ jsx22(
2912
+ ThreadsView,
2913
+ {
2914
+ config,
2915
+ threads: admin.threads,
2916
+ searchValue: threadSearch,
2917
+ onSearchChange: setThreadSearch,
2918
+ onThreadClick: handleThreadClick
2919
+ }
2920
+ );
2921
+ case "thread-detail":
2922
+ return route.resourceId ? /* @__PURE__ */ jsx22(ThreadDetailView, { threadId: route.resourceId, config, onBack: handleBackToThreads }) : null;
2923
+ case "participants":
2924
+ return /* @__PURE__ */ jsx22(
2925
+ ParticipantsView,
2926
+ {
2927
+ config,
2928
+ participants: admin.participants,
2929
+ searchValue: participantSearch,
2930
+ onSearchChange: setParticipantSearch,
2931
+ onParticipantClick: handleParticipantClick
2932
+ }
2933
+ );
2934
+ case "participant-detail":
2935
+ return route.resourceId ? /* @__PURE__ */ jsx22(ParticipantDetailView, { participantId: route.resourceId, config, onBack: handleBackToParticipants }) : null;
2936
+ case "agents":
2937
+ return /* @__PURE__ */ jsx22(
2938
+ AgentsView,
2939
+ {
2940
+ config,
2941
+ agents: admin.agents,
2942
+ searchValue: agentSearch,
2943
+ onSearchChange: setAgentSearch,
2944
+ onAgentClick: handleAgentClick
2945
+ }
2946
+ );
2947
+ case "agent-detail":
2948
+ return route.resourceId ? /* @__PURE__ */ jsx22(AgentDetailView, { agentId: route.resourceId, config, agents: admin.agents, onBack: handleBackToAgents }) : null;
2949
+ case "collection-items":
2950
+ return route.collection ? /* @__PURE__ */ jsx22(
2951
+ CollectionItemsView,
2952
+ {
2953
+ collection: route.collection,
2954
+ config,
2955
+ namespace,
2956
+ onItemClick: handleCollectionItemClick,
2957
+ onCreateNew: handleCollectionCreateNew
2958
+ }
2959
+ ) : null;
2960
+ case "collection-item-detail":
2961
+ return route.collection ? /* @__PURE__ */ jsx22(
2962
+ CollectionItemDetailView,
2963
+ {
2964
+ collection: route.collection,
2965
+ itemId: route.resourceId ?? null,
2966
+ config,
2967
+ namespace,
2968
+ onBack: handleBackToCollectionItems
2969
+ }
2970
+ ) : null;
2971
+ case "events":
2972
+ return /* @__PURE__ */ jsx22(EventsView, { config });
2973
+ default:
2974
+ return null;
2975
+ }
2976
+ };
2977
+ return /* @__PURE__ */ jsx22(TooltipProvider, { children: /* @__PURE__ */ jsx22(SidebarProvider, { defaultOpen: config.sidebar.defaultOpen, children: /* @__PURE__ */ jsxs17(
2978
+ "div",
2979
+ {
2980
+ className: cn(
2981
+ "flex h-[100svh] md:h-screen bg-background w-full overflow-hidden",
2982
+ className
2983
+ ),
2984
+ children: [
2985
+ /* @__PURE__ */ jsx22(
2986
+ AdminSidebar,
2987
+ {
2988
+ config,
2989
+ currentPage: sidebarPage,
2990
+ currentRoute: route,
2991
+ onNavigate: handleSidebarNavigate,
2992
+ onNavigateRoute: handleSidebarRouteNavigate,
2993
+ collections,
2994
+ namespace,
2995
+ onNamespaceChange: setNamespace
2996
+ }
2997
+ ),
2998
+ /* @__PURE__ */ jsx22(SidebarInset, { children: /* @__PURE__ */ jsxs17("div", { className: "flex flex-col h-full min-h-0", children: [
2999
+ /* @__PURE__ */ jsx22(
3000
+ AdminHeader,
3001
+ {
3002
+ config,
3003
+ currentRoute: route,
3004
+ range: admin.filters.range,
3005
+ interval: admin.filters.interval,
3006
+ onRangeChange: admin.setRange,
3007
+ onIntervalChange: admin.setInterval,
3008
+ onRefresh: () => void admin.refresh(),
3009
+ isLoading: admin.isLoading
3010
+ }
3011
+ ),
3012
+ /* @__PURE__ */ jsx22("div", { className: "flex-1 overflow-auto p-6", children: renderCurrentView() })
3013
+ ] }) })
3014
+ ]
3015
+ }
3016
+ ) }) });
3017
+ };
907
3018
  export {
908
3019
  CopilotzAdmin,
3020
+ createCollectionItem,
909
3021
  defaultAdminConfig,
3022
+ deleteCollectionItem,
910
3023
  fetchAdminActivity,
911
3024
  fetchAdminAgents,
912
3025
  fetchAdminOverview,
913
3026
  fetchAdminParticipants,
914
3027
  fetchAdminThreads,
3028
+ fetchCollectionItem,
3029
+ fetchCollectionItems,
3030
+ fetchCollectionNames,
3031
+ fetchParticipantDetail,
3032
+ fetchThreadEvents,
915
3033
  mergeAdminConfig,
3034
+ updateCollectionItem,
3035
+ updateParticipant,
916
3036
  useCopilotzAdmin
917
3037
  };
918
3038
  //# sourceMappingURL=index.js.map