@copilotz/admin 0.3.6 → 0.3.7
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 +1515 -291
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -20
- package/dist/index.d.ts +63 -20
- package/dist/index.js +1532 -293
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1405 -84
- package/package.json +5 -1
package/dist/index.cjs
CHANGED
|
@@ -43,13 +43,13 @@ __export(index_exports, {
|
|
|
43
43
|
module.exports = __toCommonJS(index_exports);
|
|
44
44
|
|
|
45
45
|
// src/CopilotzAdmin.tsx
|
|
46
|
-
var
|
|
46
|
+
var import_react3 = require("react");
|
|
47
47
|
|
|
48
48
|
// src/config.ts
|
|
49
49
|
var defaultAdminConfig = {
|
|
50
50
|
branding: {
|
|
51
51
|
title: "Copilotz Admin",
|
|
52
|
-
subtitle: "
|
|
52
|
+
subtitle: "Operational visibility for Copilotz clients",
|
|
53
53
|
logo: null,
|
|
54
54
|
actions: null
|
|
55
55
|
},
|
|
@@ -83,24 +83,33 @@ var defaultAdminConfig = {
|
|
|
83
83
|
scopeScoped: "Scoped",
|
|
84
84
|
configured: "Configured",
|
|
85
85
|
unconfigured: "Observed only",
|
|
86
|
-
noResults: "No results"
|
|
86
|
+
noResults: "No results",
|
|
87
|
+
eventsTitle: "Events",
|
|
88
|
+
dashboardTitle: "Dashboard"
|
|
87
89
|
},
|
|
88
90
|
features: {
|
|
89
91
|
showOverview: true,
|
|
90
92
|
showActivity: true,
|
|
91
93
|
showThreads: true,
|
|
92
94
|
showParticipants: true,
|
|
93
|
-
showAgents: true
|
|
95
|
+
showAgents: true,
|
|
96
|
+
showEvents: false
|
|
94
97
|
},
|
|
95
98
|
ui: {
|
|
96
99
|
compact: false,
|
|
97
100
|
maxActivityBars: 18
|
|
98
101
|
},
|
|
102
|
+
sidebar: {
|
|
103
|
+
defaultOpen: true,
|
|
104
|
+
collapsible: "icon"
|
|
105
|
+
},
|
|
99
106
|
baseUrl: "",
|
|
100
107
|
getRequestHeaders: async () => ({}),
|
|
101
108
|
namespace: "",
|
|
102
109
|
initialRange: "7d",
|
|
103
|
-
initialInterval: "day"
|
|
110
|
+
initialInterval: "day",
|
|
111
|
+
defaultPage: "dashboard",
|
|
112
|
+
onNavigate: null
|
|
104
113
|
};
|
|
105
114
|
function mergeAdminConfig(_baseConfig, userConfig) {
|
|
106
115
|
if (!userConfig) return defaultAdminConfig;
|
|
@@ -121,11 +130,17 @@ function mergeAdminConfig(_baseConfig, userConfig) {
|
|
|
121
130
|
...defaultAdminConfig.ui,
|
|
122
131
|
...userConfig.ui
|
|
123
132
|
},
|
|
133
|
+
sidebar: {
|
|
134
|
+
...defaultAdminConfig.sidebar,
|
|
135
|
+
...userConfig.sidebar
|
|
136
|
+
},
|
|
124
137
|
baseUrl: userConfig.baseUrl ?? defaultAdminConfig.baseUrl,
|
|
125
138
|
getRequestHeaders: userConfig.getRequestHeaders ?? defaultAdminConfig.getRequestHeaders,
|
|
126
139
|
namespace: userConfig.namespace ?? defaultAdminConfig.namespace,
|
|
127
140
|
initialRange: userConfig.initialRange ?? defaultAdminConfig.initialRange,
|
|
128
|
-
initialInterval: userConfig.initialInterval ?? defaultAdminConfig.initialInterval
|
|
141
|
+
initialInterval: userConfig.initialInterval ?? defaultAdminConfig.initialInterval,
|
|
142
|
+
defaultPage: userConfig.defaultPage ?? defaultAdminConfig.defaultPage,
|
|
143
|
+
onNavigate: userConfig.onNavigate ?? defaultAdminConfig.onNavigate
|
|
129
144
|
};
|
|
130
145
|
}
|
|
131
146
|
|
|
@@ -195,6 +210,21 @@ async function fetchAdminJson(path, params, options) {
|
|
|
195
210
|
const payload = await response.json();
|
|
196
211
|
return payload.data;
|
|
197
212
|
}
|
|
213
|
+
async function fetchRawJson(path, params, options) {
|
|
214
|
+
const url = new URL(`${resolveBaseUrl(options?.baseUrl)}${path}`, window.location.origin);
|
|
215
|
+
for (const [key, value] of Object.entries(params)) {
|
|
216
|
+
if (typeof value === "string" && value.length > 0) {
|
|
217
|
+
url.searchParams.set(key, value);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const response = await fetch(url.toString(), {
|
|
221
|
+
headers: await withAuthHeaders({}, options?.getRequestHeaders)
|
|
222
|
+
});
|
|
223
|
+
if (!response.ok) {
|
|
224
|
+
throw new Error(`Admin request failed (${response.status})`);
|
|
225
|
+
}
|
|
226
|
+
return await response.json();
|
|
227
|
+
}
|
|
198
228
|
async function fetchAdminOverview(range, namespace, options) {
|
|
199
229
|
const windowRange = getRangeWindow(range);
|
|
200
230
|
return await fetchAdminJson("/v1/admin/overview", {
|
|
@@ -233,6 +263,23 @@ async function fetchAdminAgents(search, namespace, options) {
|
|
|
233
263
|
limit: "8"
|
|
234
264
|
}, options);
|
|
235
265
|
}
|
|
266
|
+
async function fetchThreadDetail(threadId, options) {
|
|
267
|
+
return await fetchAdminJson(
|
|
268
|
+
`/v1/threads/${encodeURIComponent(threadId)}`,
|
|
269
|
+
{},
|
|
270
|
+
options
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
async function fetchThreadMessages(threadId, messageOptions, options) {
|
|
274
|
+
return await fetchRawJson(
|
|
275
|
+
`/v1/threads/${encodeURIComponent(threadId)}/messages`,
|
|
276
|
+
{
|
|
277
|
+
limit: messageOptions?.limit?.toString(),
|
|
278
|
+
before: messageOptions?.before
|
|
279
|
+
},
|
|
280
|
+
options
|
|
281
|
+
);
|
|
282
|
+
}
|
|
236
283
|
|
|
237
284
|
// src/useCopilotzAdmin.ts
|
|
238
285
|
function useCopilotzAdmin(options = {}) {
|
|
@@ -358,6 +405,19 @@ function Card({ className, ...props }) {
|
|
|
358
405
|
}
|
|
359
406
|
);
|
|
360
407
|
}
|
|
408
|
+
function CardHeader({ className, ...props }) {
|
|
409
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
410
|
+
"div",
|
|
411
|
+
{
|
|
412
|
+
"data-slot": "card-header",
|
|
413
|
+
className: cn(
|
|
414
|
+
"@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",
|
|
415
|
+
className
|
|
416
|
+
),
|
|
417
|
+
...props
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
}
|
|
361
421
|
function CardContent({ className, ...props }) {
|
|
362
422
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
363
423
|
"div",
|
|
@@ -416,10 +476,83 @@ function Button({
|
|
|
416
476
|
);
|
|
417
477
|
}
|
|
418
478
|
|
|
419
|
-
// src/components/ui/
|
|
479
|
+
// src/components/ui/tooltip.tsx
|
|
480
|
+
var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
|
|
420
481
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
421
|
-
function
|
|
482
|
+
function TooltipProvider({
|
|
483
|
+
delayDuration = 0,
|
|
484
|
+
...props
|
|
485
|
+
}) {
|
|
422
486
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
487
|
+
TooltipPrimitive.Provider,
|
|
488
|
+
{
|
|
489
|
+
"data-slot": "tooltip-provider",
|
|
490
|
+
delayDuration,
|
|
491
|
+
...props
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
function Tooltip({
|
|
496
|
+
...props
|
|
497
|
+
}) {
|
|
498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
|
|
499
|
+
}
|
|
500
|
+
function TooltipTrigger({
|
|
501
|
+
...props
|
|
502
|
+
}) {
|
|
503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
504
|
+
}
|
|
505
|
+
function TooltipContent({
|
|
506
|
+
className,
|
|
507
|
+
sideOffset = 0,
|
|
508
|
+
children,
|
|
509
|
+
...props
|
|
510
|
+
}) {
|
|
511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TooltipPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
512
|
+
TooltipPrimitive.Content,
|
|
513
|
+
{
|
|
514
|
+
"data-slot": "tooltip-content",
|
|
515
|
+
sideOffset,
|
|
516
|
+
className: cn(
|
|
517
|
+
"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",
|
|
518
|
+
className
|
|
519
|
+
),
|
|
520
|
+
...props,
|
|
521
|
+
children: [
|
|
522
|
+
children,
|
|
523
|
+
/* @__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]" })
|
|
524
|
+
]
|
|
525
|
+
}
|
|
526
|
+
) });
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/components/ui/sidebar.tsx
|
|
530
|
+
var React3 = __toESM(require("react"), 1);
|
|
531
|
+
var import_react_slot2 = require("@radix-ui/react-slot");
|
|
532
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
533
|
+
var import_lucide_react2 = require("lucide-react");
|
|
534
|
+
|
|
535
|
+
// src/hooks/use-mobile.ts
|
|
536
|
+
var React = __toESM(require("react"), 1);
|
|
537
|
+
var MOBILE_BREAKPOINT = 768;
|
|
538
|
+
function useIsMobile() {
|
|
539
|
+
const [isMobile, setIsMobile] = React.useState(void 0);
|
|
540
|
+
React.useEffect(() => {
|
|
541
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
542
|
+
const onChange = () => {
|
|
543
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
544
|
+
};
|
|
545
|
+
mql.addEventListener("change", onChange);
|
|
546
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
547
|
+
return () => mql.removeEventListener("change", onChange);
|
|
548
|
+
}, []);
|
|
549
|
+
return !!isMobile;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/components/ui/input.tsx
|
|
553
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
554
|
+
function Input({ className, type, ...props }) {
|
|
555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
423
556
|
"input",
|
|
424
557
|
{
|
|
425
558
|
type,
|
|
@@ -435,326 +568,942 @@ function Input({ className, type, ...props }) {
|
|
|
435
568
|
);
|
|
436
569
|
}
|
|
437
570
|
|
|
438
|
-
// src/components/ui/
|
|
439
|
-
var
|
|
440
|
-
var
|
|
441
|
-
var
|
|
442
|
-
var
|
|
443
|
-
|
|
444
|
-
{
|
|
445
|
-
|
|
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
|
-
}
|
|
571
|
+
// src/components/ui/sheet.tsx
|
|
572
|
+
var React2 = __toESM(require("react"), 1);
|
|
573
|
+
var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
574
|
+
var import_lucide_react = require("lucide-react");
|
|
575
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
576
|
+
function cleanupBodyStyles() {
|
|
577
|
+
if (typeof document !== "undefined" && document.body.style.pointerEvents === "none") {
|
|
578
|
+
document.body.style.pointerEvents = "";
|
|
456
579
|
}
|
|
457
|
-
|
|
458
|
-
function
|
|
580
|
+
}
|
|
581
|
+
function Sheet({ open, onOpenChange, ...props }) {
|
|
582
|
+
const prevOpenRef = React2.useRef(open);
|
|
583
|
+
React2.useEffect(() => {
|
|
584
|
+
if (prevOpenRef.current === true && open === false) {
|
|
585
|
+
const timeout = setTimeout(cleanupBodyStyles, 350);
|
|
586
|
+
return () => clearTimeout(timeout);
|
|
587
|
+
}
|
|
588
|
+
prevOpenRef.current = open;
|
|
589
|
+
}, [open]);
|
|
590
|
+
React2.useEffect(() => {
|
|
591
|
+
return () => {
|
|
592
|
+
cleanupBodyStyles();
|
|
593
|
+
};
|
|
594
|
+
}, []);
|
|
595
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SheetPrimitive.Root, { "data-slot": "sheet", open, onOpenChange, ...props });
|
|
596
|
+
}
|
|
597
|
+
function SheetPortal({
|
|
598
|
+
...props
|
|
599
|
+
}) {
|
|
600
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SheetPrimitive.Portal, { "data-slot": "sheet-portal", ...props });
|
|
601
|
+
}
|
|
602
|
+
function SheetOverlay({
|
|
459
603
|
className,
|
|
460
|
-
variant,
|
|
461
|
-
asChild = false,
|
|
462
604
|
...props
|
|
463
605
|
}) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
Comp,
|
|
606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
607
|
+
SheetPrimitive.Overlay,
|
|
467
608
|
{
|
|
468
|
-
"data-slot": "
|
|
469
|
-
className: cn(
|
|
609
|
+
"data-slot": "sheet-overlay",
|
|
610
|
+
className: cn(
|
|
611
|
+
"fixed inset-0 z-50 bg-black/50",
|
|
612
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
613
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
614
|
+
"data-[state=closed]:pointer-events-none",
|
|
615
|
+
className
|
|
616
|
+
),
|
|
470
617
|
...props
|
|
471
618
|
}
|
|
472
619
|
);
|
|
473
620
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
}
|
|
520
|
-
),
|
|
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]
|
|
552
|
-
);
|
|
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
|
-
},
|
|
621
|
+
function SheetContent({
|
|
622
|
+
className,
|
|
623
|
+
children,
|
|
624
|
+
side = "right",
|
|
625
|
+
...props
|
|
626
|
+
}) {
|
|
627
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(SheetPortal, { children: [
|
|
628
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SheetOverlay, {}),
|
|
629
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
630
|
+
SheetPrimitive.Content,
|
|
631
|
+
{
|
|
632
|
+
"data-slot": "sheet-content",
|
|
633
|
+
"aria-describedby": void 0,
|
|
634
|
+
className: cn(
|
|
635
|
+
"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",
|
|
636
|
+
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",
|
|
637
|
+
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",
|
|
638
|
+
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",
|
|
639
|
+
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",
|
|
640
|
+
className
|
|
641
|
+
),
|
|
642
|
+
...props,
|
|
643
|
+
children: [
|
|
644
|
+
children,
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.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: [
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.XIcon, { className: "size-4" }),
|
|
647
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "sr-only", children: "Close" })
|
|
648
|
+
] })
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
)
|
|
652
|
+
] });
|
|
653
|
+
}
|
|
654
|
+
function SheetHeader({ className, ...props }) {
|
|
655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
656
|
+
"div",
|
|
575
657
|
{
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
658
|
+
"data-slot": "sheet-header",
|
|
659
|
+
className: cn("flex flex-col gap-1.5 p-4", className),
|
|
660
|
+
...props
|
|
661
|
+
}
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
function SheetTitle({
|
|
665
|
+
className,
|
|
666
|
+
...props
|
|
667
|
+
}) {
|
|
668
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
669
|
+
SheetPrimitive.Title,
|
|
580
670
|
{
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
671
|
+
"data-slot": "sheet-title",
|
|
672
|
+
className: cn("text-foreground font-semibold", className),
|
|
673
|
+
...props
|
|
674
|
+
}
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
function SheetDescription({
|
|
678
|
+
className,
|
|
679
|
+
...props
|
|
680
|
+
}) {
|
|
681
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
682
|
+
SheetPrimitive.Description,
|
|
585
683
|
{
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
684
|
+
"data-slot": "sheet-description",
|
|
685
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
686
|
+
...props
|
|
687
|
+
}
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/components/ui/sidebar.tsx
|
|
692
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
693
|
+
var SIDEBAR_COOKIE_NAME = "sidebar_state";
|
|
694
|
+
var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
695
|
+
var SIDEBAR_WIDTH = "16rem";
|
|
696
|
+
var SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
697
|
+
var SIDEBAR_WIDTH_ICON = "3rem";
|
|
698
|
+
var SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
699
|
+
var SidebarContext = React3.createContext(null);
|
|
700
|
+
function useSidebar() {
|
|
701
|
+
const context = React3.useContext(SidebarContext);
|
|
702
|
+
if (!context) {
|
|
703
|
+
throw new Error("useSidebar must be used within a SidebarProvider.");
|
|
704
|
+
}
|
|
705
|
+
return context;
|
|
706
|
+
}
|
|
707
|
+
function SidebarProvider({
|
|
708
|
+
defaultOpen = true,
|
|
709
|
+
open: openProp,
|
|
710
|
+
onOpenChange: setOpenProp,
|
|
711
|
+
className,
|
|
712
|
+
style,
|
|
713
|
+
children,
|
|
714
|
+
...props
|
|
715
|
+
}) {
|
|
716
|
+
const isMobile = useIsMobile();
|
|
717
|
+
const [openMobile, setOpenMobile] = React3.useState(false);
|
|
718
|
+
const [_open, _setOpen] = React3.useState(defaultOpen);
|
|
719
|
+
const open = openProp ?? _open;
|
|
720
|
+
const setOpen = React3.useCallback(
|
|
721
|
+
(value) => {
|
|
722
|
+
const openState = typeof value === "function" ? value(open) : value;
|
|
723
|
+
if (setOpenProp) {
|
|
724
|
+
setOpenProp(openState);
|
|
725
|
+
} else {
|
|
726
|
+
_setOpen(openState);
|
|
727
|
+
}
|
|
728
|
+
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
589
729
|
},
|
|
730
|
+
[setOpenProp, open]
|
|
731
|
+
);
|
|
732
|
+
const toggleSidebar = React3.useCallback(() => {
|
|
733
|
+
return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
|
|
734
|
+
}, [isMobile, setOpen, setOpenMobile]);
|
|
735
|
+
React3.useEffect(() => {
|
|
736
|
+
const handleKeyDown = (event) => {
|
|
737
|
+
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
738
|
+
event.preventDefault();
|
|
739
|
+
toggleSidebar();
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
743
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
744
|
+
}, [toggleSidebar]);
|
|
745
|
+
const state = open ? "expanded" : "collapsed";
|
|
746
|
+
const contextValue = React3.useMemo(
|
|
747
|
+
() => ({
|
|
748
|
+
state,
|
|
749
|
+
open,
|
|
750
|
+
setOpen,
|
|
751
|
+
isMobile,
|
|
752
|
+
openMobile,
|
|
753
|
+
setOpenMobile,
|
|
754
|
+
toggleSidebar
|
|
755
|
+
}),
|
|
756
|
+
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
|
757
|
+
);
|
|
758
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
759
|
+
"div",
|
|
590
760
|
{
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
761
|
+
"data-slot": "sidebar-wrapper",
|
|
762
|
+
style: {
|
|
763
|
+
"--sidebar-width": SIDEBAR_WIDTH,
|
|
764
|
+
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
765
|
+
...style
|
|
766
|
+
},
|
|
767
|
+
className: cn(
|
|
768
|
+
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
|
|
769
|
+
className
|
|
770
|
+
),
|
|
771
|
+
...props,
|
|
772
|
+
children
|
|
594
773
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
774
|
+
) }) });
|
|
775
|
+
}
|
|
776
|
+
function Sidebar({
|
|
777
|
+
side = "left",
|
|
778
|
+
variant = "sidebar",
|
|
779
|
+
collapsible = "offcanvas",
|
|
780
|
+
className,
|
|
781
|
+
children,
|
|
782
|
+
...props
|
|
783
|
+
}) {
|
|
784
|
+
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
785
|
+
if (collapsible === "none") {
|
|
786
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
787
|
+
"div",
|
|
788
|
+
{
|
|
789
|
+
"data-slot": "sidebar",
|
|
790
|
+
className: cn(
|
|
791
|
+
"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
|
|
792
|
+
className
|
|
793
|
+
),
|
|
794
|
+
...props,
|
|
795
|
+
children
|
|
796
|
+
}
|
|
797
|
+
);
|
|
598
798
|
}
|
|
599
|
-
if (
|
|
600
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
799
|
+
if (isMobile) {
|
|
800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
801
|
+
SheetContent,
|
|
802
|
+
{
|
|
803
|
+
"data-sidebar": "sidebar",
|
|
804
|
+
"data-slot": "sidebar",
|
|
805
|
+
"data-mobile": "true",
|
|
806
|
+
className: "bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden",
|
|
807
|
+
style: {
|
|
808
|
+
"--sidebar-width": SIDEBAR_WIDTH_MOBILE
|
|
809
|
+
},
|
|
810
|
+
side,
|
|
811
|
+
children: [
|
|
812
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(SheetHeader, { className: "sr-only", children: [
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SheetTitle, { children: "Sidebar" }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SheetDescription, { children: "Displays the mobile sidebar." })
|
|
815
|
+
] }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex h-full w-full flex-col", children })
|
|
817
|
+
]
|
|
818
|
+
}
|
|
819
|
+
) });
|
|
611
820
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
822
|
+
"div",
|
|
823
|
+
{
|
|
824
|
+
className: "group peer text-sidebar-foreground hidden md:block",
|
|
825
|
+
"data-state": state,
|
|
826
|
+
"data-collapsible": state === "collapsed" ? collapsible : "",
|
|
827
|
+
"data-variant": variant,
|
|
828
|
+
"data-side": side,
|
|
829
|
+
"data-slot": "sidebar",
|
|
830
|
+
children: [
|
|
831
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
832
|
+
"div",
|
|
833
|
+
{
|
|
834
|
+
"data-slot": "sidebar-gap",
|
|
835
|
+
className: cn(
|
|
836
|
+
"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
|
|
837
|
+
"group-data-[collapsible=offcanvas]:w-0",
|
|
838
|
+
"group-data-[side=right]:rotate-180",
|
|
839
|
+
variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
|
|
840
|
+
)
|
|
841
|
+
}
|
|
842
|
+
),
|
|
629
843
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
844
|
+
"div",
|
|
845
|
+
{
|
|
846
|
+
"data-slot": "sidebar-container",
|
|
847
|
+
className: cn(
|
|
848
|
+
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
|
|
849
|
+
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)]",
|
|
850
|
+
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",
|
|
851
|
+
className
|
|
852
|
+
),
|
|
853
|
+
...props,
|
|
854
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
855
|
+
"div",
|
|
856
|
+
{
|
|
857
|
+
"data-sidebar": "sidebar",
|
|
858
|
+
"data-slot": "sidebar-inner",
|
|
859
|
+
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",
|
|
860
|
+
children
|
|
861
|
+
}
|
|
862
|
+
)
|
|
863
|
+
}
|
|
864
|
+
)
|
|
865
|
+
]
|
|
866
|
+
}
|
|
867
|
+
);
|
|
868
|
+
}
|
|
869
|
+
function SidebarTrigger({
|
|
870
|
+
className,
|
|
871
|
+
onClick,
|
|
872
|
+
...props
|
|
873
|
+
}) {
|
|
874
|
+
const { toggleSidebar } = useSidebar();
|
|
875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
876
|
+
Button,
|
|
877
|
+
{
|
|
878
|
+
"data-sidebar": "trigger",
|
|
879
|
+
"data-slot": "sidebar-trigger",
|
|
880
|
+
variant: "ghost",
|
|
881
|
+
size: "icon",
|
|
882
|
+
className: cn("size-7", className),
|
|
883
|
+
onClick: (event) => {
|
|
884
|
+
onClick?.(event);
|
|
885
|
+
toggleSidebar();
|
|
886
|
+
},
|
|
887
|
+
...props,
|
|
888
|
+
children: [
|
|
889
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react2.PanelLeftIcon, {}),
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "sr-only", children: "Toggle Sidebar" })
|
|
891
|
+
]
|
|
892
|
+
}
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
function SidebarRail({ className, ...props }) {
|
|
896
|
+
const { toggleSidebar } = useSidebar();
|
|
897
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
898
|
+
"button",
|
|
899
|
+
{
|
|
900
|
+
"data-sidebar": "rail",
|
|
901
|
+
"data-slot": "sidebar-rail",
|
|
902
|
+
"aria-label": "Toggle Sidebar",
|
|
903
|
+
tabIndex: -1,
|
|
904
|
+
onClick: toggleSidebar,
|
|
905
|
+
title: "Toggle Sidebar",
|
|
906
|
+
className: cn(
|
|
907
|
+
"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",
|
|
908
|
+
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
|
|
909
|
+
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
|
910
|
+
"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
|
|
911
|
+
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
|
|
912
|
+
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
|
|
913
|
+
className
|
|
914
|
+
),
|
|
915
|
+
...props
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
function SidebarInset({ className, ...props }) {
|
|
920
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
921
|
+
"main",
|
|
922
|
+
{
|
|
923
|
+
"data-slot": "sidebar-inset",
|
|
924
|
+
className: cn(
|
|
925
|
+
"bg-background relative flex w-full flex-1 flex-col",
|
|
926
|
+
"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",
|
|
927
|
+
className
|
|
928
|
+
),
|
|
929
|
+
...props
|
|
930
|
+
}
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
function SidebarHeader({ className, ...props }) {
|
|
934
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
935
|
+
"div",
|
|
936
|
+
{
|
|
937
|
+
"data-slot": "sidebar-header",
|
|
938
|
+
"data-sidebar": "header",
|
|
939
|
+
className: cn("flex flex-col gap-2 p-2", className),
|
|
940
|
+
...props
|
|
941
|
+
}
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
function SidebarFooter({ className, ...props }) {
|
|
945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
946
|
+
"div",
|
|
947
|
+
{
|
|
948
|
+
"data-slot": "sidebar-footer",
|
|
949
|
+
"data-sidebar": "footer",
|
|
950
|
+
className: cn("flex flex-col gap-2 p-2", className),
|
|
951
|
+
...props
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
function SidebarContent({ className, ...props }) {
|
|
956
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
957
|
+
"div",
|
|
958
|
+
{
|
|
959
|
+
"data-slot": "sidebar-content",
|
|
960
|
+
"data-sidebar": "content",
|
|
961
|
+
className: cn(
|
|
962
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
|
|
963
|
+
className
|
|
964
|
+
),
|
|
965
|
+
...props
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
function SidebarGroup({ className, ...props }) {
|
|
970
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
971
|
+
"div",
|
|
972
|
+
{
|
|
973
|
+
"data-slot": "sidebar-group",
|
|
974
|
+
"data-sidebar": "group",
|
|
975
|
+
className: cn("relative flex w-full min-w-0 flex-col p-2", className),
|
|
976
|
+
...props
|
|
977
|
+
}
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
function SidebarGroupLabel({
|
|
981
|
+
className,
|
|
982
|
+
asChild = false,
|
|
983
|
+
...props
|
|
984
|
+
}) {
|
|
985
|
+
const Comp = asChild ? import_react_slot2.Slot : "div";
|
|
986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
987
|
+
Comp,
|
|
988
|
+
{
|
|
989
|
+
"data-slot": "sidebar-group-label",
|
|
990
|
+
"data-sidebar": "group-label",
|
|
991
|
+
className: cn(
|
|
992
|
+
"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",
|
|
993
|
+
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
|
994
|
+
className
|
|
995
|
+
),
|
|
996
|
+
...props
|
|
997
|
+
}
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
function SidebarGroupContent({
|
|
1001
|
+
className,
|
|
1002
|
+
...props
|
|
1003
|
+
}) {
|
|
1004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1005
|
+
"div",
|
|
1006
|
+
{
|
|
1007
|
+
"data-slot": "sidebar-group-content",
|
|
1008
|
+
"data-sidebar": "group-content",
|
|
1009
|
+
className: cn("w-full text-sm", className),
|
|
1010
|
+
...props
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
function SidebarMenu({ className, ...props }) {
|
|
1015
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1016
|
+
"ul",
|
|
1017
|
+
{
|
|
1018
|
+
"data-slot": "sidebar-menu",
|
|
1019
|
+
"data-sidebar": "menu",
|
|
1020
|
+
className: cn("flex w-full min-w-0 flex-col gap-1", className),
|
|
1021
|
+
...props
|
|
1022
|
+
}
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
function SidebarMenuItem({ className, ...props }) {
|
|
1026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1027
|
+
"li",
|
|
1028
|
+
{
|
|
1029
|
+
"data-slot": "sidebar-menu-item",
|
|
1030
|
+
"data-sidebar": "menu-item",
|
|
1031
|
+
className: cn("group/menu-item relative", className),
|
|
1032
|
+
...props
|
|
1033
|
+
}
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
var sidebarMenuButtonVariants = (0, import_class_variance_authority2.cva)(
|
|
1037
|
+
"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",
|
|
1038
|
+
{
|
|
1039
|
+
variants: {
|
|
1040
|
+
variant: {
|
|
1041
|
+
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
1042
|
+
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))]"
|
|
1043
|
+
},
|
|
1044
|
+
size: {
|
|
1045
|
+
default: "h-8 text-sm",
|
|
1046
|
+
sm: "h-7 text-xs",
|
|
1047
|
+
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!"
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
defaultVariants: {
|
|
1051
|
+
variant: "default",
|
|
1052
|
+
size: "default"
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
);
|
|
1056
|
+
function SidebarMenuButton({
|
|
1057
|
+
asChild = false,
|
|
1058
|
+
isActive = false,
|
|
1059
|
+
variant = "default",
|
|
1060
|
+
size = "default",
|
|
1061
|
+
tooltip,
|
|
1062
|
+
className,
|
|
1063
|
+
...props
|
|
1064
|
+
}) {
|
|
1065
|
+
const Comp = asChild ? import_react_slot2.Slot : "button";
|
|
1066
|
+
const { isMobile, state } = useSidebar();
|
|
1067
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1068
|
+
Comp,
|
|
1069
|
+
{
|
|
1070
|
+
"data-slot": "sidebar-menu-button",
|
|
1071
|
+
"data-sidebar": "menu-button",
|
|
1072
|
+
"data-size": size,
|
|
1073
|
+
"data-active": isActive,
|
|
1074
|
+
className: cn(sidebarMenuButtonVariants({ variant, size }), className),
|
|
1075
|
+
...props
|
|
1076
|
+
}
|
|
1077
|
+
);
|
|
1078
|
+
if (!tooltip) {
|
|
1079
|
+
return button;
|
|
1080
|
+
}
|
|
1081
|
+
if (typeof tooltip === "string") {
|
|
1082
|
+
tooltip = {
|
|
1083
|
+
children: tooltip
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Tooltip, { children: [
|
|
1087
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TooltipTrigger, { asChild: true, children: button }),
|
|
1088
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1089
|
+
TooltipContent,
|
|
1090
|
+
{
|
|
1091
|
+
side: "right",
|
|
1092
|
+
align: "center",
|
|
1093
|
+
hidden: state !== "collapsed" || isMobile,
|
|
1094
|
+
...tooltip
|
|
1095
|
+
}
|
|
1096
|
+
)
|
|
1097
|
+
] });
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// src/components/layout/AdminSidebar.tsx
|
|
1101
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1102
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1103
|
+
var NAV_ITEMS = [
|
|
1104
|
+
{
|
|
1105
|
+
page: "dashboard",
|
|
1106
|
+
label: "Dashboard",
|
|
1107
|
+
icon: import_lucide_react3.LayoutDashboard
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
page: "threads",
|
|
1111
|
+
label: "Threads",
|
|
1112
|
+
icon: import_lucide_react3.MessageSquare,
|
|
1113
|
+
featureKey: "showThreads"
|
|
1114
|
+
},
|
|
1115
|
+
{
|
|
1116
|
+
page: "participants",
|
|
1117
|
+
label: "Participants",
|
|
1118
|
+
icon: import_lucide_react3.Users,
|
|
1119
|
+
featureKey: "showParticipants"
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
page: "agents",
|
|
1123
|
+
label: "Agents",
|
|
1124
|
+
icon: import_lucide_react3.Bot,
|
|
1125
|
+
featureKey: "showAgents"
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
page: "events",
|
|
1129
|
+
label: "Events",
|
|
1130
|
+
icon: import_lucide_react3.Activity,
|
|
1131
|
+
featureKey: "showEvents"
|
|
1132
|
+
}
|
|
1133
|
+
];
|
|
1134
|
+
var AdminSidebar = ({
|
|
1135
|
+
config,
|
|
1136
|
+
currentPage,
|
|
1137
|
+
onNavigate
|
|
1138
|
+
}) => {
|
|
1139
|
+
const visibleItems = NAV_ITEMS.filter(
|
|
1140
|
+
(item) => !item.featureKey || config.features[item.featureKey]
|
|
1141
|
+
);
|
|
1142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Sidebar, { collapsible: config.sidebar.collapsible, children: [
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-3 px-2 py-3", children: [
|
|
1144
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex items-center justify-center shrink-0", children: config.branding.logo || /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-primary text-primary-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.LayoutDashboard, { className: "h-4 w-4" }) }) }),
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col min-w-0 group-data-[collapsible=icon]:hidden", children: [
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm font-semibold truncate", children: config.branding.title }),
|
|
1147
|
+
config.branding.subtitle && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-xs text-muted-foreground truncate", children: config.branding.subtitle })
|
|
1148
|
+
] })
|
|
1149
|
+
] }) }),
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarContent, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(SidebarGroup, { children: [
|
|
1151
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarGroupLabel, { className: "group-data-[collapsible=icon]:hidden", children: "Navigation" }),
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarGroupContent, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarMenu, { children: visibleItems.map((item) => {
|
|
1153
|
+
const Icon2 = item.icon;
|
|
1154
|
+
const label = config.labels[`${item.page}Title`] || item.label;
|
|
1155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarMenuItem, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1156
|
+
SidebarMenuButton,
|
|
1157
|
+
{
|
|
1158
|
+
isActive: currentPage === item.page,
|
|
1159
|
+
onClick: () => onNavigate(item.page),
|
|
1160
|
+
tooltip: label,
|
|
1161
|
+
children: [
|
|
1162
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon2, {}),
|
|
1163
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: label })
|
|
1164
|
+
]
|
|
1165
|
+
}
|
|
1166
|
+
) }, item.page);
|
|
1167
|
+
}) }) })
|
|
1168
|
+
] }) }),
|
|
1169
|
+
config.namespace && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarFooter, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "px-2 py-2 text-xs text-muted-foreground group-data-[collapsible=icon]:hidden", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-medium uppercase tracking-[0.18em]", children: config.namespace }) }) }),
|
|
1170
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarRail, {})
|
|
1171
|
+
] });
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
// src/components/layout/AdminHeader.tsx
|
|
1175
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1176
|
+
|
|
1177
|
+
// src/components/ui/select.tsx
|
|
1178
|
+
var React4 = __toESM(require("react"), 1);
|
|
1179
|
+
var SelectPrimitive = __toESM(require("@radix-ui/react-select"), 1);
|
|
1180
|
+
var import_lucide_react4 = require("lucide-react");
|
|
1181
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1182
|
+
var Select = SelectPrimitive.Root;
|
|
1183
|
+
var SelectValue = SelectPrimitive.Value;
|
|
1184
|
+
var SelectTrigger = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1185
|
+
SelectPrimitive.Trigger,
|
|
1186
|
+
{
|
|
1187
|
+
ref,
|
|
1188
|
+
className: cn(
|
|
1189
|
+
"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",
|
|
1190
|
+
className
|
|
1191
|
+
),
|
|
1192
|
+
...props,
|
|
1193
|
+
children: [
|
|
1194
|
+
children,
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
1196
|
+
]
|
|
1197
|
+
}
|
|
1198
|
+
));
|
|
1199
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
1200
|
+
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)(
|
|
1201
|
+
SelectPrimitive.Content,
|
|
1202
|
+
{
|
|
1203
|
+
ref,
|
|
1204
|
+
className: cn(
|
|
1205
|
+
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md",
|
|
1206
|
+
position === "popper" && "translate-y-1",
|
|
1207
|
+
className
|
|
1208
|
+
),
|
|
1209
|
+
position,
|
|
1210
|
+
...props,
|
|
1211
|
+
children: [
|
|
1212
|
+
/* @__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_react4.ChevronUp, { className: "h-4 w-4" }) }),
|
|
1213
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1214
|
+
SelectPrimitive.Viewport,
|
|
1215
|
+
{
|
|
1216
|
+
className: cn(
|
|
1217
|
+
"p-1",
|
|
1218
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
1219
|
+
),
|
|
1220
|
+
children
|
|
1221
|
+
}
|
|
1222
|
+
),
|
|
1223
|
+
/* @__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_react4.ChevronDown, { className: "h-4 w-4" }) })
|
|
1224
|
+
]
|
|
1225
|
+
}
|
|
1226
|
+
) }));
|
|
1227
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
1228
|
+
var SelectItem = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
1229
|
+
SelectPrimitive.Item,
|
|
1230
|
+
{
|
|
1231
|
+
ref,
|
|
1232
|
+
className: cn(
|
|
1233
|
+
"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",
|
|
1234
|
+
className
|
|
1235
|
+
),
|
|
1236
|
+
...props,
|
|
1237
|
+
children: [
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SelectPrimitive.ItemText, { children }),
|
|
1239
|
+
/* @__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_react4.Check, { className: "h-4 w-4" }) })
|
|
1240
|
+
]
|
|
1241
|
+
}
|
|
1242
|
+
));
|
|
1243
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
1244
|
+
|
|
1245
|
+
// src/components/layout/AdminHeader.tsx
|
|
1246
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1247
|
+
var PAGE_TITLES = {
|
|
1248
|
+
dashboard: "Dashboard",
|
|
1249
|
+
threads: "Threads",
|
|
1250
|
+
"thread-detail": "Thread Detail",
|
|
1251
|
+
participants: "Participants",
|
|
1252
|
+
agents: "Agents",
|
|
1253
|
+
events: "Events"
|
|
1254
|
+
};
|
|
1255
|
+
var AdminHeader = ({
|
|
1256
|
+
config,
|
|
1257
|
+
currentPage,
|
|
1258
|
+
range,
|
|
1259
|
+
interval,
|
|
1260
|
+
onRangeChange,
|
|
1261
|
+
onIntervalChange,
|
|
1262
|
+
onRefresh,
|
|
1263
|
+
isLoading
|
|
1264
|
+
}) => {
|
|
1265
|
+
const pageTitle = config.labels[`${currentPage}Title`] || PAGE_TITLES[currentPage];
|
|
1266
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.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_runtime9.jsx)(CardHeader, { className: "p-2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { children: [
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SidebarTrigger, { className: "-ml-1" }) }),
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { children: "Toggle Sidebar" })
|
|
1271
|
+
] }),
|
|
1272
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { className: "text-sm font-medium ml-2", children: pageTitle })
|
|
1273
|
+
] }),
|
|
1274
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1" }),
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
1276
|
+
currentPage === "dashboard" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
1277
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
630
1278
|
Button,
|
|
631
1279
|
{
|
|
632
|
-
variant:
|
|
1280
|
+
variant: range === "24h" ? "default" : "ghost",
|
|
633
1281
|
size: "sm",
|
|
634
|
-
|
|
1282
|
+
className: "h-7 text-xs",
|
|
1283
|
+
onClick: () => onRangeChange("24h"),
|
|
635
1284
|
children: config.labels.range24h
|
|
636
1285
|
}
|
|
637
1286
|
),
|
|
638
|
-
/* @__PURE__ */ (0,
|
|
1287
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
639
1288
|
Button,
|
|
640
1289
|
{
|
|
641
|
-
variant:
|
|
1290
|
+
variant: range === "7d" ? "default" : "ghost",
|
|
642
1291
|
size: "sm",
|
|
643
|
-
|
|
1292
|
+
className: "h-7 text-xs",
|
|
1293
|
+
onClick: () => onRangeChange("7d"),
|
|
644
1294
|
children: config.labels.range7d
|
|
645
1295
|
}
|
|
646
1296
|
),
|
|
647
|
-
/* @__PURE__ */ (0,
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
648
1298
|
Button,
|
|
649
1299
|
{
|
|
650
|
-
variant:
|
|
1300
|
+
variant: range === "30d" ? "default" : "ghost",
|
|
651
1301
|
size: "sm",
|
|
652
|
-
|
|
1302
|
+
className: "h-7 text-xs",
|
|
1303
|
+
onClick: () => onRangeChange("30d"),
|
|
653
1304
|
children: config.labels.range30d
|
|
654
1305
|
}
|
|
655
1306
|
),
|
|
656
|
-
/* @__PURE__ */ (0,
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
657
1308
|
Select,
|
|
658
1309
|
{
|
|
659
|
-
value:
|
|
660
|
-
onValueChange: (v) =>
|
|
1310
|
+
value: interval,
|
|
1311
|
+
onValueChange: (v) => onIntervalChange(v),
|
|
661
1312
|
children: [
|
|
662
|
-
/* @__PURE__ */ (0,
|
|
663
|
-
/* @__PURE__ */ (0,
|
|
664
|
-
/* @__PURE__ */ (0,
|
|
665
|
-
/* @__PURE__ */ (0,
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectTrigger, { className: "h-7 w-[90px] text-xs", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectValue, {}) }),
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(SelectContent, { children: [
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectItem, { value: "hour", children: config.labels.intervalHour }),
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SelectItem, { value: "day", children: config.labels.intervalDay })
|
|
666
1317
|
] })
|
|
667
1318
|
]
|
|
668
1319
|
}
|
|
669
|
-
)
|
|
670
|
-
|
|
1320
|
+
)
|
|
1321
|
+
] }),
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { children: [
|
|
1323
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
671
1324
|
Button,
|
|
672
1325
|
{
|
|
673
|
-
variant: "
|
|
674
|
-
size: "
|
|
675
|
-
|
|
676
|
-
|
|
1326
|
+
variant: "ghost",
|
|
1327
|
+
size: "icon",
|
|
1328
|
+
className: "h-7 w-7",
|
|
1329
|
+
onClick: onRefresh,
|
|
1330
|
+
disabled: isLoading,
|
|
1331
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1332
|
+
import_lucide_react5.RefreshCw,
|
|
1333
|
+
{
|
|
1334
|
+
className: `h-4 w-4 ${isLoading ? "animate-spin" : ""}`
|
|
1335
|
+
}
|
|
1336
|
+
)
|
|
677
1337
|
}
|
|
678
|
-
),
|
|
679
|
-
config.
|
|
680
|
-
] })
|
|
1338
|
+
) }),
|
|
1339
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { children: config.labels.refresh })
|
|
1340
|
+
] }),
|
|
1341
|
+
config.branding.actions
|
|
1342
|
+
] })
|
|
1343
|
+
] }) }) });
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1346
|
+
// src/components/ui/badge.tsx
|
|
1347
|
+
var import_react_slot3 = require("@radix-ui/react-slot");
|
|
1348
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
1349
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1350
|
+
var badgeVariants = (0, import_class_variance_authority3.cva)(
|
|
1351
|
+
"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",
|
|
1352
|
+
{
|
|
1353
|
+
variants: {
|
|
1354
|
+
variant: {
|
|
1355
|
+
default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
1356
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
1357
|
+
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",
|
|
1358
|
+
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
defaultVariants: {
|
|
1362
|
+
variant: "default"
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
);
|
|
1366
|
+
function Badge({
|
|
1367
|
+
className,
|
|
1368
|
+
variant,
|
|
1369
|
+
asChild = false,
|
|
1370
|
+
...props
|
|
1371
|
+
}) {
|
|
1372
|
+
const Comp = asChild ? import_react_slot3.Slot : "span";
|
|
1373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1374
|
+
Comp,
|
|
1375
|
+
{
|
|
1376
|
+
"data-slot": "badge",
|
|
1377
|
+
className: cn(badgeVariants({ variant }), className),
|
|
1378
|
+
...props
|
|
1379
|
+
}
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// src/components/views/DashboardView.tsx
|
|
1384
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1385
|
+
var DashboardView = ({
|
|
1386
|
+
config,
|
|
1387
|
+
overview,
|
|
1388
|
+
activity,
|
|
1389
|
+
threads,
|
|
1390
|
+
participants,
|
|
1391
|
+
agents,
|
|
1392
|
+
interval,
|
|
1393
|
+
threadSearch,
|
|
1394
|
+
participantSearch,
|
|
1395
|
+
agentSearch,
|
|
1396
|
+
onThreadSearchChange,
|
|
1397
|
+
onParticipantSearchChange,
|
|
1398
|
+
onAgentSearchChange,
|
|
1399
|
+
onThreadClick
|
|
1400
|
+
}) => {
|
|
1401
|
+
const cards = [
|
|
1402
|
+
{
|
|
1403
|
+
label: config.labels.messagesCard,
|
|
1404
|
+
value: overview?.messageTotals.total ?? 0,
|
|
1405
|
+
detail: `${overview?.messageTotals.toolCallMessages ?? 0} tool-call messages`
|
|
1406
|
+
},
|
|
1407
|
+
{
|
|
1408
|
+
label: config.labels.activeThreadsCard,
|
|
1409
|
+
value: overview?.threadTotals.active ?? 0,
|
|
1410
|
+
detail: `${overview?.threadTotals.total ?? 0} total threads`
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
label: config.labels.participantsCard,
|
|
1414
|
+
value: overview?.participantTotals.total ?? 0,
|
|
1415
|
+
detail: `${overview?.participantTotals.agents ?? 0} agents`
|
|
1416
|
+
},
|
|
1417
|
+
{
|
|
1418
|
+
label: config.labels.tokensCard,
|
|
1419
|
+
value: overview?.llmTotals.totalTokens ?? 0,
|
|
1420
|
+
detail: `${overview?.llmTotals.totalCalls ?? 0} calls`
|
|
1421
|
+
},
|
|
1422
|
+
{
|
|
1423
|
+
label: config.labels.queueCard,
|
|
1424
|
+
value: overview?.queueTotals.pending ?? 0,
|
|
1425
|
+
detail: `${overview?.queueTotals.failed ?? 0} failed`
|
|
1426
|
+
}
|
|
1427
|
+
];
|
|
1428
|
+
const isEmpty = cards.every((card) => card.value === 0) && activity.length === 0 && threads.length === 0 && participants.length === 0 && agents.length === 0;
|
|
1429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "space-y-6", children: [
|
|
1430
|
+
isEmpty && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-lg font-semibold", children: config.labels.emptyTitle }),
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "mt-2 text-sm text-muted-foreground", children: config.labels.emptyDescription })
|
|
681
1433
|
] }),
|
|
682
|
-
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
684
|
-
/* @__PURE__ */ (0,
|
|
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)(
|
|
1434
|
+
config.features.showOverview && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: "space-y-4", children: [
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionHeading, { title: config.labels.overviewTitle }),
|
|
1436
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.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_runtime11.jsxs)(
|
|
689
1437
|
"div",
|
|
690
1438
|
{
|
|
691
|
-
className: "rounded-xl border bg-
|
|
1439
|
+
className: "rounded-xl border bg-card p-5 shadow-sm",
|
|
692
1440
|
children: [
|
|
693
|
-
/* @__PURE__ */ (0,
|
|
694
|
-
/* @__PURE__ */ (0,
|
|
695
|
-
/* @__PURE__ */ (0,
|
|
1441
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-sm font-medium text-muted-foreground", children: card.label }),
|
|
1442
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "mt-3 text-3xl font-semibold tracking-tight", children: formatNumber(card.value) }),
|
|
1443
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: card.detail })
|
|
696
1444
|
]
|
|
697
1445
|
},
|
|
698
1446
|
card.label
|
|
699
1447
|
)) })
|
|
700
|
-
] })
|
|
701
|
-
config.features.showActivity
|
|
702
|
-
/* @__PURE__ */ (0,
|
|
703
|
-
/* @__PURE__ */ (0,
|
|
1448
|
+
] }),
|
|
1449
|
+
config.features.showActivity && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: "space-y-4", children: [
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionHeading, { title: config.labels.activityTitle }),
|
|
1451
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
704
1452
|
ActivityChart,
|
|
705
1453
|
{
|
|
706
|
-
interval
|
|
1454
|
+
interval,
|
|
707
1455
|
labels: config.labels,
|
|
708
1456
|
maxBars: config.ui.maxActivityBars,
|
|
709
|
-
points:
|
|
1457
|
+
points: activity
|
|
710
1458
|
}
|
|
711
1459
|
)
|
|
712
|
-
] })
|
|
713
|
-
/* @__PURE__ */ (0,
|
|
714
|
-
config.features.showThreads
|
|
1460
|
+
] }),
|
|
1461
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid gap-6 lg:grid-cols-3", children: [
|
|
1462
|
+
config.features.showThreads && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
715
1463
|
DataTable,
|
|
716
1464
|
{
|
|
717
|
-
rows:
|
|
1465
|
+
rows: threads,
|
|
718
1466
|
searchPlaceholder: config.labels.threadSearchPlaceholder,
|
|
719
1467
|
searchValue: threadSearch,
|
|
720
|
-
setSearchValue:
|
|
1468
|
+
setSearchValue: onThreadSearchChange,
|
|
721
1469
|
title: config.labels.threadsTitle,
|
|
722
|
-
children: /* @__PURE__ */ (0,
|
|
1470
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1471
|
+
ThreadsTable,
|
|
1472
|
+
{
|
|
1473
|
+
rows: threads,
|
|
1474
|
+
labels: config.labels,
|
|
1475
|
+
onThreadClick
|
|
1476
|
+
}
|
|
1477
|
+
)
|
|
723
1478
|
}
|
|
724
|
-
)
|
|
725
|
-
config.features.showParticipants
|
|
1479
|
+
),
|
|
1480
|
+
config.features.showParticipants && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
726
1481
|
DataTable,
|
|
727
1482
|
{
|
|
728
|
-
rows:
|
|
1483
|
+
rows: participants,
|
|
729
1484
|
searchPlaceholder: config.labels.participantSearchPlaceholder,
|
|
730
1485
|
searchValue: participantSearch,
|
|
731
|
-
setSearchValue:
|
|
1486
|
+
setSearchValue: onParticipantSearchChange,
|
|
732
1487
|
title: config.labels.participantsTitle,
|
|
733
|
-
children: /* @__PURE__ */ (0,
|
|
734
|
-
ParticipantsTable,
|
|
735
|
-
{
|
|
736
|
-
rows: admin.participants,
|
|
737
|
-
labels: config.labels
|
|
738
|
-
}
|
|
739
|
-
)
|
|
1488
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ParticipantsTable, { rows: participants, labels: config.labels })
|
|
740
1489
|
}
|
|
741
|
-
)
|
|
742
|
-
config.features.showAgents
|
|
1490
|
+
),
|
|
1491
|
+
config.features.showAgents && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
743
1492
|
DataTable,
|
|
744
1493
|
{
|
|
745
|
-
rows:
|
|
1494
|
+
rows: agents,
|
|
746
1495
|
searchPlaceholder: config.labels.agentSearchPlaceholder,
|
|
747
1496
|
searchValue: agentSearch,
|
|
748
|
-
setSearchValue:
|
|
1497
|
+
setSearchValue: onAgentSearchChange,
|
|
749
1498
|
title: config.labels.agentsTitle,
|
|
750
|
-
children: /* @__PURE__ */ (0,
|
|
1499
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentsTable, { rows: agents, labels: config.labels })
|
|
751
1500
|
}
|
|
752
|
-
)
|
|
1501
|
+
)
|
|
753
1502
|
] })
|
|
754
|
-
] })
|
|
1503
|
+
] });
|
|
755
1504
|
};
|
|
756
1505
|
function SectionHeading({ title }) {
|
|
757
|
-
return /* @__PURE__ */ (0,
|
|
1506
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-lg font-semibold tracking-tight", children: title });
|
|
758
1507
|
}
|
|
759
1508
|
function ActivityChart(props) {
|
|
760
1509
|
const trimmedPoints = props.points.slice(-props.maxBars);
|
|
@@ -762,12 +1511,12 @@ function ActivityChart(props) {
|
|
|
762
1511
|
...trimmedPoints.map((point) => point.messageCount),
|
|
763
1512
|
1
|
|
764
1513
|
);
|
|
765
|
-
return /* @__PURE__ */ (0,
|
|
1514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: trimmedPoints.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-sm text-muted-foreground", children: props.labels.noResults }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex min-h-48 items-end gap-2", children: trimmedPoints.map((point) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
766
1515
|
"div",
|
|
767
1516
|
{
|
|
768
1517
|
className: "flex min-w-0 flex-1 flex-col items-center gap-2",
|
|
769
1518
|
children: [
|
|
770
|
-
/* @__PURE__ */ (0,
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex h-36 w-full items-end rounded-lg bg-muted px-1 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
771
1520
|
"div",
|
|
772
1521
|
{
|
|
773
1522
|
className: "w-full rounded-md bg-primary transition-all",
|
|
@@ -776,9 +1525,9 @@ function ActivityChart(props) {
|
|
|
776
1525
|
}
|
|
777
1526
|
}
|
|
778
1527
|
) }),
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
780
|
-
/* @__PURE__ */ (0,
|
|
781
|
-
/* @__PURE__ */ (0,
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-center", children: [
|
|
1529
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-xs font-medium", children: formatBucket(point.bucket, props.interval) }),
|
|
1530
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { className: "text-[11px] text-muted-foreground", children: [
|
|
782
1531
|
formatNumber(point.messageCount),
|
|
783
1532
|
" msg"
|
|
784
1533
|
] })
|
|
@@ -789,10 +1538,10 @@ function ActivityChart(props) {
|
|
|
789
1538
|
)) }) });
|
|
790
1539
|
}
|
|
791
1540
|
function DataTable(props) {
|
|
792
|
-
return /* @__PURE__ */ (0,
|
|
793
|
-
/* @__PURE__ */ (0,
|
|
794
|
-
/* @__PURE__ */ (0,
|
|
795
|
-
/* @__PURE__ */ (0,
|
|
1541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mb-4 flex items-center justify-between gap-3", children: [
|
|
1543
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionHeading, { title: props.title }),
|
|
1544
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
796
1545
|
Input,
|
|
797
1546
|
{
|
|
798
1547
|
className: "h-8 w-full max-w-44",
|
|
@@ -802,24 +1551,29 @@ function DataTable(props) {
|
|
|
802
1551
|
}
|
|
803
1552
|
)
|
|
804
1553
|
] }),
|
|
805
|
-
props.rows.length === 0 ? /* @__PURE__ */ (0,
|
|
1554
|
+
props.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-sm text-muted-foreground", children: "No results" }) : props.children
|
|
806
1555
|
] });
|
|
807
1556
|
}
|
|
808
1557
|
function ThreadsTable({
|
|
809
1558
|
rows,
|
|
810
|
-
labels
|
|
1559
|
+
labels,
|
|
1560
|
+
onThreadClick
|
|
811
1561
|
}) {
|
|
812
|
-
return /* @__PURE__ */ (0,
|
|
1562
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-3", children: rows.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
813
1563
|
"div",
|
|
814
1564
|
{
|
|
815
|
-
className:
|
|
1565
|
+
className: cn(
|
|
1566
|
+
"rounded-lg border bg-muted/50 p-4",
|
|
1567
|
+
onThreadClick && "cursor-pointer hover:bg-muted transition-colors"
|
|
1568
|
+
),
|
|
1569
|
+
onClick: () => onThreadClick?.(thread.threadId),
|
|
816
1570
|
children: [
|
|
817
|
-
/* @__PURE__ */ (0,
|
|
818
|
-
/* @__PURE__ */ (0,
|
|
819
|
-
/* @__PURE__ */ (0,
|
|
820
|
-
/* @__PURE__ */ (0,
|
|
1571
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1572
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "min-w-0", children: [
|
|
1573
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "font-medium", children: thread.name }),
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: thread.summary ?? thread.lastMessagePreview ?? "No summary yet" })
|
|
821
1575
|
] }),
|
|
822
|
-
/* @__PURE__ */ (0,
|
|
1576
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
823
1577
|
Badge,
|
|
824
1578
|
{
|
|
825
1579
|
variant: thread.status === "archived" ? "secondary" : "default",
|
|
@@ -827,16 +1581,16 @@ function ThreadsTable({
|
|
|
827
1581
|
}
|
|
828
1582
|
)
|
|
829
1583
|
] }),
|
|
830
|
-
/* @__PURE__ */ (0,
|
|
831
|
-
/* @__PURE__ */ (0,
|
|
1584
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mt-3 flex flex-wrap gap-3 text-xs text-muted-foreground", children: [
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
832
1586
|
formatNumber(thread.messageCount),
|
|
833
1587
|
" messages"
|
|
834
1588
|
] }),
|
|
835
|
-
/* @__PURE__ */ (0,
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
836
1590
|
thread.participantIds.length,
|
|
837
1591
|
" participants"
|
|
838
1592
|
] }),
|
|
839
|
-
/* @__PURE__ */ (0,
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: formatDate(thread.lastActivityAt) })
|
|
840
1594
|
] })
|
|
841
1595
|
]
|
|
842
1596
|
},
|
|
@@ -847,28 +1601,28 @@ function ParticipantsTable({
|
|
|
847
1601
|
rows,
|
|
848
1602
|
labels
|
|
849
1603
|
}) {
|
|
850
|
-
return /* @__PURE__ */ (0,
|
|
1604
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-3", children: rows.map((participant) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
851
1605
|
"div",
|
|
852
1606
|
{
|
|
853
1607
|
className: "rounded-lg border bg-muted/50 p-4",
|
|
854
1608
|
children: [
|
|
855
|
-
/* @__PURE__ */ (0,
|
|
856
|
-
/* @__PURE__ */ (0,
|
|
857
|
-
/* @__PURE__ */ (0,
|
|
858
|
-
/* @__PURE__ */ (0,
|
|
1609
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1610
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "min-w-0", children: [
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "font-medium", children: participant.displayName }),
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "mt-1 text-xs uppercase tracking-[0.18em] text-muted-foreground", children: participant.participantType })
|
|
859
1613
|
] }),
|
|
860
|
-
/* @__PURE__ */ (0,
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Badge, { variant: "outline", children: participant.isGlobal ? labels.scopeGlobal : labels.scopeScoped })
|
|
861
1615
|
] }),
|
|
862
|
-
/* @__PURE__ */ (0,
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
1616
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mt-3 flex flex-wrap gap-3 text-xs text-muted-foreground", children: [
|
|
1617
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
864
1618
|
formatNumber(participant.messageCount),
|
|
865
1619
|
" messages"
|
|
866
1620
|
] }),
|
|
867
|
-
/* @__PURE__ */ (0,
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
868
1622
|
formatNumber(participant.threadCount),
|
|
869
1623
|
" threads"
|
|
870
1624
|
] }),
|
|
871
|
-
/* @__PURE__ */ (0,
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: formatDate(participant.lastActivityAt) })
|
|
872
1626
|
] })
|
|
873
1627
|
]
|
|
874
1628
|
},
|
|
@@ -879,32 +1633,32 @@ function AgentsTable({
|
|
|
879
1633
|
rows,
|
|
880
1634
|
labels
|
|
881
1635
|
}) {
|
|
882
|
-
return /* @__PURE__ */ (0,
|
|
1636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-3", children: rows.map((agent) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
883
1637
|
"div",
|
|
884
1638
|
{
|
|
885
1639
|
className: "rounded-lg border bg-muted/50 p-4",
|
|
886
1640
|
children: [
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
888
|
-
/* @__PURE__ */ (0,
|
|
889
|
-
/* @__PURE__ */ (0,
|
|
890
|
-
/* @__PURE__ */ (0,
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "min-w-0", children: [
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "font-medium", children: agent.displayName }),
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: agent.description ?? agent.agentId })
|
|
891
1645
|
] }),
|
|
892
|
-
/* @__PURE__ */ (0,
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Badge, { variant: "outline", children: agent.isConfigured ? labels.configured : labels.unconfigured })
|
|
893
1647
|
] }),
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
/* @__PURE__ */ (0,
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mt-3 grid grid-cols-2 gap-2 text-xs text-muted-foreground", children: [
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
896
1650
|
formatNumber(agent.messageCount),
|
|
897
1651
|
" messages"
|
|
898
1652
|
] }),
|
|
899
|
-
/* @__PURE__ */ (0,
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
900
1654
|
formatNumber(agent.llmCallCount),
|
|
901
1655
|
" LLM calls"
|
|
902
1656
|
] }),
|
|
903
|
-
/* @__PURE__ */ (0,
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
904
1658
|
formatNumber(agent.toolCallMessageCount),
|
|
905
1659
|
" tool calls"
|
|
906
1660
|
] }),
|
|
907
|
-
/* @__PURE__ */ (0,
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
908
1662
|
formatNumber(agent.totalTokens),
|
|
909
1663
|
" tokens"
|
|
910
1664
|
] })
|
|
@@ -940,6 +1694,476 @@ function formatDate(value) {
|
|
|
940
1694
|
function formatNumber(value) {
|
|
941
1695
|
return new Intl.NumberFormat().format(value);
|
|
942
1696
|
}
|
|
1697
|
+
|
|
1698
|
+
// src/components/views/ThreadsView.tsx
|
|
1699
|
+
var import_lucide_react6 = require("lucide-react");
|
|
1700
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1701
|
+
var ThreadsView = ({
|
|
1702
|
+
config,
|
|
1703
|
+
threads,
|
|
1704
|
+
searchValue,
|
|
1705
|
+
onSearchChange,
|
|
1706
|
+
onThreadClick
|
|
1707
|
+
}) => {
|
|
1708
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-4", children: [
|
|
1709
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative max-w-sm", children: [
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.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" }),
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1712
|
+
Input,
|
|
1713
|
+
{
|
|
1714
|
+
className: "pl-9",
|
|
1715
|
+
placeholder: config.labels.threadSearchPlaceholder,
|
|
1716
|
+
value: searchValue,
|
|
1717
|
+
onChange: (e) => onSearchChange(e.target.value)
|
|
1718
|
+
}
|
|
1719
|
+
)
|
|
1720
|
+
] }),
|
|
1721
|
+
threads.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
|
|
1722
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react6.MessageSquare, { className: "mx-auto h-8 w-8 text-muted-foreground/50" }),
|
|
1723
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "mt-3 text-sm text-muted-foreground", children: searchValue ? config.labels.noResults : config.labels.emptyDescription })
|
|
1724
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "space-y-2", children: threads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1725
|
+
"div",
|
|
1726
|
+
{
|
|
1727
|
+
className: "flex items-center gap-4 rounded-lg border bg-card p-4 transition-colors hover:bg-muted/50 cursor-pointer",
|
|
1728
|
+
onClick: () => onThreadClick?.(thread.threadId),
|
|
1729
|
+
children: [
|
|
1730
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
1731
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1732
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "font-medium truncate", children: thread.name }),
|
|
1733
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1734
|
+
Badge,
|
|
1735
|
+
{
|
|
1736
|
+
variant: thread.status === "archived" ? "secondary" : "default",
|
|
1737
|
+
className: "shrink-0",
|
|
1738
|
+
children: thread.status === "archived" ? config.labels.statusArchived : config.labels.statusActive
|
|
1739
|
+
}
|
|
1740
|
+
)
|
|
1741
|
+
] }),
|
|
1742
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "mt-1 text-sm text-muted-foreground truncate", children: thread.summary ?? thread.lastMessagePreview ?? "No summary yet" })
|
|
1743
|
+
] }),
|
|
1744
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "text-right text-xs text-muted-foreground shrink-0 space-y-1", children: [
|
|
1745
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { children: [
|
|
1746
|
+
formatNumber2(thread.messageCount),
|
|
1747
|
+
" messages"
|
|
1748
|
+
] }),
|
|
1749
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { children: [
|
|
1750
|
+
thread.participantIds.length,
|
|
1751
|
+
" participants"
|
|
1752
|
+
] }),
|
|
1753
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { children: formatDate2(thread.lastActivityAt) })
|
|
1754
|
+
] })
|
|
1755
|
+
]
|
|
1756
|
+
},
|
|
1757
|
+
thread.threadId
|
|
1758
|
+
)) })
|
|
1759
|
+
] });
|
|
1760
|
+
};
|
|
1761
|
+
function formatDate2(value) {
|
|
1762
|
+
if (!value) return "No activity";
|
|
1763
|
+
const date = new Date(value);
|
|
1764
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
1765
|
+
return date.toLocaleString(void 0, {
|
|
1766
|
+
month: "short",
|
|
1767
|
+
day: "numeric",
|
|
1768
|
+
hour: "numeric",
|
|
1769
|
+
minute: "2-digit"
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
function formatNumber2(value) {
|
|
1773
|
+
return new Intl.NumberFormat().format(value);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
// src/components/views/ThreadDetailView.tsx
|
|
1777
|
+
var import_react2 = require("react");
|
|
1778
|
+
var import_lucide_react7 = require("lucide-react");
|
|
1779
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1780
|
+
var MESSAGES_PAGE_SIZE = 50;
|
|
1781
|
+
var ThreadDetailView = ({
|
|
1782
|
+
threadId,
|
|
1783
|
+
config,
|
|
1784
|
+
onBack
|
|
1785
|
+
}) => {
|
|
1786
|
+
const [thread, setThread] = (0, import_react2.useState)(null);
|
|
1787
|
+
const [messages, setMessages] = (0, import_react2.useState)([]);
|
|
1788
|
+
const [pageInfo, setPageInfo] = (0, import_react2.useState)(null);
|
|
1789
|
+
const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
|
|
1790
|
+
const [isLoadingMore, setIsLoadingMore] = (0, import_react2.useState)(false);
|
|
1791
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
1792
|
+
const fetchOptions = {
|
|
1793
|
+
baseUrl: config.baseUrl,
|
|
1794
|
+
getRequestHeaders: config.getRequestHeaders
|
|
1795
|
+
};
|
|
1796
|
+
const loadInitial = (0, import_react2.useCallback)(async () => {
|
|
1797
|
+
setIsLoading(true);
|
|
1798
|
+
setError(null);
|
|
1799
|
+
try {
|
|
1800
|
+
const [threadData, messagesData] = await Promise.all([
|
|
1801
|
+
fetchThreadDetail(threadId, fetchOptions),
|
|
1802
|
+
fetchThreadMessages(threadId, { limit: MESSAGES_PAGE_SIZE }, fetchOptions)
|
|
1803
|
+
]);
|
|
1804
|
+
setThread(threadData);
|
|
1805
|
+
setMessages(messagesData.data);
|
|
1806
|
+
setPageInfo(messagesData.pageInfo);
|
|
1807
|
+
} catch (err) {
|
|
1808
|
+
setError(
|
|
1809
|
+
err instanceof Error ? err : new Error("Failed to load thread")
|
|
1810
|
+
);
|
|
1811
|
+
} finally {
|
|
1812
|
+
setIsLoading(false);
|
|
1813
|
+
}
|
|
1814
|
+
}, [threadId, config.baseUrl, config.getRequestHeaders]);
|
|
1815
|
+
(0, import_react2.useEffect)(() => {
|
|
1816
|
+
void loadInitial();
|
|
1817
|
+
}, [loadInitial]);
|
|
1818
|
+
const loadMore = (0, import_react2.useCallback)(async () => {
|
|
1819
|
+
if (!pageInfo?.hasMoreBefore || !pageInfo.oldestMessageId || isLoadingMore) {
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1822
|
+
setIsLoadingMore(true);
|
|
1823
|
+
try {
|
|
1824
|
+
const older = await fetchThreadMessages(
|
|
1825
|
+
threadId,
|
|
1826
|
+
{ limit: MESSAGES_PAGE_SIZE, before: pageInfo.oldestMessageId },
|
|
1827
|
+
fetchOptions
|
|
1828
|
+
);
|
|
1829
|
+
setMessages((prev) => [...older.data, ...prev]);
|
|
1830
|
+
setPageInfo(older.pageInfo);
|
|
1831
|
+
} catch {
|
|
1832
|
+
} finally {
|
|
1833
|
+
setIsLoadingMore(false);
|
|
1834
|
+
}
|
|
1835
|
+
}, [threadId, pageInfo, isLoadingMore, config.baseUrl, config.getRequestHeaders]);
|
|
1836
|
+
if (isLoading) {
|
|
1837
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground" }) });
|
|
1838
|
+
}
|
|
1839
|
+
if (error) {
|
|
1840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-4 py-10 text-center", children: [
|
|
1841
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-destructive font-medium", children: error.message }),
|
|
1842
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex justify-center gap-2", children: [
|
|
1843
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Button, { variant: "outline", onClick: onBack, children: [
|
|
1844
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.ArrowLeft, { className: "mr-2 h-4 w-4" }),
|
|
1845
|
+
"Back"
|
|
1846
|
+
] }),
|
|
1847
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Button, { variant: "destructive", onClick: () => void loadInitial(), children: config.labels.retry })
|
|
1848
|
+
] })
|
|
1849
|
+
] });
|
|
1850
|
+
}
|
|
1851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-6", children: [
|
|
1852
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-start gap-4", children: [
|
|
1853
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1854
|
+
Button,
|
|
1855
|
+
{
|
|
1856
|
+
variant: "ghost",
|
|
1857
|
+
size: "icon",
|
|
1858
|
+
className: "mt-1 shrink-0",
|
|
1859
|
+
onClick: onBack,
|
|
1860
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.ArrowLeft, { className: "h-4 w-4" })
|
|
1861
|
+
}
|
|
1862
|
+
),
|
|
1863
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
1864
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-xl font-semibold truncate", children: thread?.name ?? threadId }),
|
|
1866
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1867
|
+
Badge,
|
|
1868
|
+
{
|
|
1869
|
+
variant: thread?.status === "archived" ? "secondary" : "default",
|
|
1870
|
+
children: thread?.status === "archived" ? config.labels.statusArchived : config.labels.statusActive
|
|
1871
|
+
}
|
|
1872
|
+
)
|
|
1873
|
+
] }),
|
|
1874
|
+
thread?.summary && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: thread.summary }),
|
|
1875
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mt-2 flex flex-wrap gap-4 text-xs text-muted-foreground", children: [
|
|
1876
|
+
thread?.createdAt && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1877
|
+
"Created ",
|
|
1878
|
+
formatDate3(thread.createdAt)
|
|
1879
|
+
] }),
|
|
1880
|
+
thread?.updatedAt && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1881
|
+
"Updated ",
|
|
1882
|
+
formatDate3(thread.updatedAt)
|
|
1883
|
+
] }),
|
|
1884
|
+
thread?.participants && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1885
|
+
thread.participants.length,
|
|
1886
|
+
" participants"
|
|
1887
|
+
] })
|
|
1888
|
+
] })
|
|
1889
|
+
] })
|
|
1890
|
+
] }),
|
|
1891
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-1", children: [
|
|
1892
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("h3", { className: "text-sm font-medium text-muted-foreground", children: [
|
|
1893
|
+
"Messages (",
|
|
1894
|
+
messages.length,
|
|
1895
|
+
pageInfo?.hasMoreBefore ? "+" : "",
|
|
1896
|
+
")"
|
|
1897
|
+
] }) }),
|
|
1898
|
+
pageInfo?.hasMoreBefore && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1899
|
+
Button,
|
|
1900
|
+
{
|
|
1901
|
+
variant: "ghost",
|
|
1902
|
+
size: "sm",
|
|
1903
|
+
onClick: () => void loadMore(),
|
|
1904
|
+
disabled: isLoadingMore,
|
|
1905
|
+
children: [
|
|
1906
|
+
isLoadingMore ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Loader2, { className: "mr-2 h-3 w-3 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.ChevronUp, { className: "mr-2 h-3 w-3" }),
|
|
1907
|
+
"Load older messages"
|
|
1908
|
+
]
|
|
1909
|
+
}
|
|
1910
|
+
) }),
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rounded-lg border bg-card", children: messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "p-6 text-center text-sm text-muted-foreground", children: "No messages in this thread yet." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "divide-y", children: messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MessageRow, { message }, message.id)) }) })
|
|
1912
|
+
] })
|
|
1913
|
+
] });
|
|
1914
|
+
};
|
|
1915
|
+
function MessageRow({ message }) {
|
|
1916
|
+
const [expanded, setExpanded] = (0, import_react2.useState)(false);
|
|
1917
|
+
const hasToolCalls = Array.isArray(message.toolCalls) && message.toolCalls.length > 0;
|
|
1918
|
+
const hasReasoning = !!message.reasoning;
|
|
1919
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-start gap-3", children: [
|
|
1920
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SenderIcon, { senderType: message.senderType }),
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
1922
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "font-medium", children: message.senderId ?? message.senderUserId ?? message.senderType }),
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", className: "text-[10px] px-1.5 py-0", children: message.senderType }),
|
|
1925
|
+
message.createdAt && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-muted-foreground", children: formatTimestamp(message.createdAt) })
|
|
1926
|
+
] }),
|
|
1927
|
+
message.content && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mt-1 text-sm whitespace-pre-wrap break-words", children: message.content }),
|
|
1928
|
+
(hasToolCalls || hasReasoning) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mt-2 space-y-2", children: [
|
|
1929
|
+
hasToolCalls && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1930
|
+
"button",
|
|
1931
|
+
{
|
|
1932
|
+
type: "button",
|
|
1933
|
+
onClick: () => setExpanded(!expanded),
|
|
1934
|
+
className: "inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors",
|
|
1935
|
+
children: [
|
|
1936
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Wrench, { className: "h-3 w-3" }),
|
|
1937
|
+
message.toolCalls.length,
|
|
1938
|
+
" tool call",
|
|
1939
|
+
message.toolCalls.length > 1 ? "s" : ""
|
|
1940
|
+
]
|
|
1941
|
+
}
|
|
1942
|
+
),
|
|
1943
|
+
hasReasoning && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1944
|
+
"button",
|
|
1945
|
+
{
|
|
1946
|
+
type: "button",
|
|
1947
|
+
onClick: () => setExpanded(!expanded),
|
|
1948
|
+
className: "inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors",
|
|
1949
|
+
children: [
|
|
1950
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Cpu, { className: "h-3 w-3" }),
|
|
1951
|
+
"Reasoning"
|
|
1952
|
+
]
|
|
1953
|
+
}
|
|
1954
|
+
),
|
|
1955
|
+
expanded && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "mt-2 rounded-md bg-muted p-3 text-xs overflow-auto max-h-60", children: JSON.stringify(
|
|
1956
|
+
{
|
|
1957
|
+
...hasToolCalls ? { toolCalls: message.toolCalls } : {},
|
|
1958
|
+
...hasReasoning ? { reasoning: message.reasoning } : {}
|
|
1959
|
+
},
|
|
1960
|
+
null,
|
|
1961
|
+
2
|
|
1962
|
+
) })
|
|
1963
|
+
] })
|
|
1964
|
+
] })
|
|
1965
|
+
] }) });
|
|
1966
|
+
}
|
|
1967
|
+
function SenderIcon({ senderType }) {
|
|
1968
|
+
const base = "flex h-7 w-7 shrink-0 items-center justify-center rounded-full";
|
|
1969
|
+
switch (senderType) {
|
|
1970
|
+
case "agent":
|
|
1971
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn(base, "bg-primary/10 text-primary"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Bot, { className: "h-3.5 w-3.5" }) });
|
|
1972
|
+
case "user":
|
|
1973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn(base, "bg-secondary text-secondary-foreground"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.User, { className: "h-3.5 w-3.5" }) });
|
|
1974
|
+
case "tool":
|
|
1975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn(base, "bg-muted text-muted-foreground"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Wrench, { className: "h-3.5 w-3.5" }) });
|
|
1976
|
+
default:
|
|
1977
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn(base, "bg-muted text-muted-foreground"), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Cpu, { className: "h-3.5 w-3.5" }) });
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
function formatDate3(value) {
|
|
1981
|
+
const date = new Date(value);
|
|
1982
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
1983
|
+
return date.toLocaleDateString(void 0, {
|
|
1984
|
+
month: "short",
|
|
1985
|
+
day: "numeric",
|
|
1986
|
+
year: "numeric"
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
function formatTimestamp(value) {
|
|
1990
|
+
const date = new Date(value);
|
|
1991
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
1992
|
+
return date.toLocaleString(void 0, {
|
|
1993
|
+
month: "short",
|
|
1994
|
+
day: "numeric",
|
|
1995
|
+
hour: "numeric",
|
|
1996
|
+
minute: "2-digit",
|
|
1997
|
+
second: "2-digit"
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
// src/CopilotzAdmin.tsx
|
|
2002
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2003
|
+
var CopilotzAdmin = ({
|
|
2004
|
+
config: userConfig,
|
|
2005
|
+
className
|
|
2006
|
+
}) => {
|
|
2007
|
+
const config = (0, import_react3.useMemo)(
|
|
2008
|
+
() => mergeAdminConfig(defaultAdminConfig, userConfig),
|
|
2009
|
+
[userConfig]
|
|
2010
|
+
);
|
|
2011
|
+
const [route, setRoute] = (0, import_react3.useState)({ page: config.defaultPage });
|
|
2012
|
+
const [threadSearch, setThreadSearch] = (0, import_react3.useState)("");
|
|
2013
|
+
const [participantSearch, setParticipantSearch] = (0, import_react3.useState)("");
|
|
2014
|
+
const [agentSearch, setAgentSearch] = (0, import_react3.useState)("");
|
|
2015
|
+
const deferredThreadSearch = (0, import_react3.useDeferredValue)(threadSearch);
|
|
2016
|
+
const deferredParticipantSearch = (0, import_react3.useDeferredValue)(participantSearch);
|
|
2017
|
+
const deferredAgentSearch = (0, import_react3.useDeferredValue)(agentSearch);
|
|
2018
|
+
const admin = useCopilotzAdmin({
|
|
2019
|
+
baseUrl: config.baseUrl,
|
|
2020
|
+
getRequestHeaders: config.getRequestHeaders,
|
|
2021
|
+
namespace: config.namespace,
|
|
2022
|
+
range: config.initialRange,
|
|
2023
|
+
interval: config.initialInterval,
|
|
2024
|
+
threadSearch: deferredThreadSearch,
|
|
2025
|
+
participantSearch: deferredParticipantSearch,
|
|
2026
|
+
agentSearch: deferredAgentSearch
|
|
2027
|
+
});
|
|
2028
|
+
const navigate = (0, import_react3.useCallback)(
|
|
2029
|
+
(next) => {
|
|
2030
|
+
setRoute(next);
|
|
2031
|
+
config.onNavigate?.(next);
|
|
2032
|
+
},
|
|
2033
|
+
[config]
|
|
2034
|
+
);
|
|
2035
|
+
const handleSidebarNavigate = (0, import_react3.useCallback)(
|
|
2036
|
+
(page) => navigate({ page }),
|
|
2037
|
+
[navigate]
|
|
2038
|
+
);
|
|
2039
|
+
const handleThreadClick = (0, import_react3.useCallback)(
|
|
2040
|
+
(threadId) => navigate({ page: "thread-detail", resourceId: threadId }),
|
|
2041
|
+
[navigate]
|
|
2042
|
+
);
|
|
2043
|
+
const handleBackToThreads = (0, import_react3.useCallback)(
|
|
2044
|
+
() => navigate({ page: "threads" }),
|
|
2045
|
+
[navigate]
|
|
2046
|
+
);
|
|
2047
|
+
const sidebarPage = route.page === "thread-detail" ? "threads" : route.page;
|
|
2048
|
+
if (admin.isLoading && !admin.overview) {
|
|
2049
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Card, { className: cn("border-border", className), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CardContent, { className: "text-muted-foreground flex items-center justify-center min-h-[200px]", children: config.labels.loading }) });
|
|
2050
|
+
}
|
|
2051
|
+
if (admin.error && !admin.overview) {
|
|
2052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2053
|
+
Card,
|
|
2054
|
+
{
|
|
2055
|
+
className: cn("border-destructive/50 bg-destructive/10", className),
|
|
2056
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(CardContent, { className: "space-y-4", children: [
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-base font-semibold text-destructive", children: admin.error.message }),
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2059
|
+
Button,
|
|
2060
|
+
{
|
|
2061
|
+
variant: "destructive",
|
|
2062
|
+
onClick: () => void admin.refresh(),
|
|
2063
|
+
children: config.labels.retry
|
|
2064
|
+
}
|
|
2065
|
+
)
|
|
2066
|
+
] })
|
|
2067
|
+
}
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
const renderCurrentView = () => {
|
|
2071
|
+
switch (route.page) {
|
|
2072
|
+
case "dashboard":
|
|
2073
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2074
|
+
DashboardView,
|
|
2075
|
+
{
|
|
2076
|
+
config,
|
|
2077
|
+
overview: admin.overview,
|
|
2078
|
+
activity: admin.activity,
|
|
2079
|
+
threads: admin.threads,
|
|
2080
|
+
participants: admin.participants,
|
|
2081
|
+
agents: admin.agents,
|
|
2082
|
+
interval: admin.filters.interval,
|
|
2083
|
+
threadSearch,
|
|
2084
|
+
participantSearch,
|
|
2085
|
+
agentSearch,
|
|
2086
|
+
onThreadSearchChange: setThreadSearch,
|
|
2087
|
+
onParticipantSearchChange: setParticipantSearch,
|
|
2088
|
+
onAgentSearchChange: setAgentSearch,
|
|
2089
|
+
onThreadClick: handleThreadClick
|
|
2090
|
+
}
|
|
2091
|
+
);
|
|
2092
|
+
case "threads":
|
|
2093
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2094
|
+
ThreadsView,
|
|
2095
|
+
{
|
|
2096
|
+
config,
|
|
2097
|
+
threads: admin.threads,
|
|
2098
|
+
searchValue: threadSearch,
|
|
2099
|
+
onSearchChange: setThreadSearch,
|
|
2100
|
+
onThreadClick: handleThreadClick
|
|
2101
|
+
}
|
|
2102
|
+
);
|
|
2103
|
+
case "thread-detail":
|
|
2104
|
+
return route.resourceId ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2105
|
+
ThreadDetailView,
|
|
2106
|
+
{
|
|
2107
|
+
threadId: route.resourceId,
|
|
2108
|
+
config,
|
|
2109
|
+
onBack: handleBackToThreads
|
|
2110
|
+
}
|
|
2111
|
+
) : null;
|
|
2112
|
+
case "participants":
|
|
2113
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
|
|
2114
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-lg font-semibold", children: config.labels.participantsTitle }),
|
|
2115
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mt-2 text-sm text-muted-foreground", children: "Detailed participant management coming soon." })
|
|
2116
|
+
] });
|
|
2117
|
+
case "agents":
|
|
2118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
|
|
2119
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-lg font-semibold", children: config.labels.agentsTitle }),
|
|
2120
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mt-2 text-sm text-muted-foreground", children: "Agent configuration management coming soon." })
|
|
2121
|
+
] });
|
|
2122
|
+
case "events":
|
|
2123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rounded-xl border border-dashed p-10 text-center", children: [
|
|
2124
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-lg font-semibold", children: config.labels.eventsTitle }),
|
|
2125
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mt-2 text-sm text-muted-foreground", children: "Event inspector coming soon." })
|
|
2126
|
+
] });
|
|
2127
|
+
default:
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2131
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SidebarProvider, { defaultOpen: config.sidebar.defaultOpen, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
2132
|
+
"div",
|
|
2133
|
+
{
|
|
2134
|
+
className: cn(
|
|
2135
|
+
"flex h-[100svh] md:h-screen bg-background w-full overflow-hidden",
|
|
2136
|
+
className
|
|
2137
|
+
),
|
|
2138
|
+
children: [
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2140
|
+
AdminSidebar,
|
|
2141
|
+
{
|
|
2142
|
+
config,
|
|
2143
|
+
currentPage: sidebarPage,
|
|
2144
|
+
onNavigate: handleSidebarNavigate
|
|
2145
|
+
}
|
|
2146
|
+
),
|
|
2147
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SidebarInset, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col h-full min-h-0", children: [
|
|
2148
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2149
|
+
AdminHeader,
|
|
2150
|
+
{
|
|
2151
|
+
config,
|
|
2152
|
+
currentPage: route.page,
|
|
2153
|
+
range: admin.filters.range,
|
|
2154
|
+
interval: admin.filters.interval,
|
|
2155
|
+
onRangeChange: admin.setRange,
|
|
2156
|
+
onIntervalChange: admin.setInterval,
|
|
2157
|
+
onRefresh: () => void admin.refresh(),
|
|
2158
|
+
isLoading: admin.isLoading
|
|
2159
|
+
}
|
|
2160
|
+
),
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex-1 overflow-auto p-6", children: renderCurrentView() })
|
|
2162
|
+
] }) })
|
|
2163
|
+
]
|
|
2164
|
+
}
|
|
2165
|
+
) }) });
|
|
2166
|
+
};
|
|
943
2167
|
// Annotate the CommonJS export names for ESM import in node:
|
|
944
2168
|
0 && (module.exports = {
|
|
945
2169
|
CopilotzAdmin,
|