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