@copilotz/admin 0.3.5 → 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 +1526 -295
- 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 +1543 -297
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1432 -111
- 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,319 +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
|
-
|
|
629
|
-
|
|
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
|
+
),
|
|
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 })
|
|
1433
|
+
] }),
|
|
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)(
|
|
1437
|
+
"div",
|
|
1438
|
+
{
|
|
1439
|
+
className: "rounded-xl border bg-card p-5 shadow-sm",
|
|
1440
|
+
children: [
|
|
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 })
|
|
1444
|
+
]
|
|
1445
|
+
},
|
|
1446
|
+
card.label
|
|
1447
|
+
)) })
|
|
681
1448
|
] }),
|
|
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 gap-4 md:grid-cols-2 xl:grid-cols-5", children: cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Card, { className: "gap-0 py-0", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(CardContent, { className: "p-5", children: [
|
|
689
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "text-sm font-medium text-muted-foreground", children: card.label }),
|
|
690
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mt-3 text-3xl font-semibold tracking-tight", children: formatNumber(card.value) }),
|
|
691
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mt-2 text-xs text-muted-foreground", children: card.detail })
|
|
692
|
-
] }) }, card.label)) })
|
|
693
|
-
] }) : null,
|
|
694
|
-
config.features.showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "space-y-4", children: [
|
|
695
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SectionHeading, { title: config.labels.activityTitle }),
|
|
696
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
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)(
|
|
697
1452
|
ActivityChart,
|
|
698
1453
|
{
|
|
699
|
-
interval
|
|
1454
|
+
interval,
|
|
700
1455
|
labels: config.labels,
|
|
701
1456
|
maxBars: config.ui.maxActivityBars,
|
|
702
|
-
points:
|
|
1457
|
+
points: activity
|
|
703
1458
|
}
|
|
704
1459
|
)
|
|
705
|
-
] })
|
|
706
|
-
/* @__PURE__ */ (0,
|
|
707
|
-
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)(
|
|
708
1463
|
DataTable,
|
|
709
1464
|
{
|
|
710
|
-
rows:
|
|
1465
|
+
rows: threads,
|
|
711
1466
|
searchPlaceholder: config.labels.threadSearchPlaceholder,
|
|
712
1467
|
searchValue: threadSearch,
|
|
713
|
-
setSearchValue:
|
|
1468
|
+
setSearchValue: onThreadSearchChange,
|
|
714
1469
|
title: config.labels.threadsTitle,
|
|
715
|
-
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
|
+
)
|
|
716
1478
|
}
|
|
717
|
-
)
|
|
718
|
-
config.features.showParticipants
|
|
1479
|
+
),
|
|
1480
|
+
config.features.showParticipants && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
719
1481
|
DataTable,
|
|
720
1482
|
{
|
|
721
|
-
rows:
|
|
1483
|
+
rows: participants,
|
|
722
1484
|
searchPlaceholder: config.labels.participantSearchPlaceholder,
|
|
723
1485
|
searchValue: participantSearch,
|
|
724
|
-
setSearchValue:
|
|
1486
|
+
setSearchValue: onParticipantSearchChange,
|
|
725
1487
|
title: config.labels.participantsTitle,
|
|
726
|
-
children: /* @__PURE__ */ (0,
|
|
727
|
-
ParticipantsTable,
|
|
728
|
-
{
|
|
729
|
-
rows: admin.participants,
|
|
730
|
-
labels: config.labels
|
|
731
|
-
}
|
|
732
|
-
)
|
|
1488
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ParticipantsTable, { rows: participants, labels: config.labels })
|
|
733
1489
|
}
|
|
734
|
-
)
|
|
735
|
-
config.features.showAgents
|
|
1490
|
+
),
|
|
1491
|
+
config.features.showAgents && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
736
1492
|
DataTable,
|
|
737
1493
|
{
|
|
738
|
-
rows:
|
|
1494
|
+
rows: agents,
|
|
739
1495
|
searchPlaceholder: config.labels.agentSearchPlaceholder,
|
|
740
1496
|
searchValue: agentSearch,
|
|
741
|
-
setSearchValue:
|
|
1497
|
+
setSearchValue: onAgentSearchChange,
|
|
742
1498
|
title: config.labels.agentsTitle,
|
|
743
|
-
children: /* @__PURE__ */ (0,
|
|
1499
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AgentsTable, { rows: agents, labels: config.labels })
|
|
744
1500
|
}
|
|
745
|
-
)
|
|
1501
|
+
)
|
|
746
1502
|
] })
|
|
747
1503
|
] });
|
|
748
1504
|
};
|
|
749
1505
|
function SectionHeading({ title }) {
|
|
750
|
-
return /* @__PURE__ */ (0,
|
|
1506
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-lg font-semibold tracking-tight", children: title });
|
|
751
1507
|
}
|
|
752
1508
|
function ActivityChart(props) {
|
|
753
1509
|
const trimmedPoints = props.points.slice(-props.maxBars);
|
|
@@ -755,23 +1511,23 @@ function ActivityChart(props) {
|
|
|
755
1511
|
...trimmedPoints.map((point) => point.messageCount),
|
|
756
1512
|
1
|
|
757
1513
|
);
|
|
758
|
-
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)(
|
|
759
1515
|
"div",
|
|
760
1516
|
{
|
|
761
1517
|
className: "flex min-w-0 flex-1 flex-col items-center gap-2",
|
|
762
1518
|
children: [
|
|
763
|
-
/* @__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)(
|
|
764
1520
|
"div",
|
|
765
1521
|
{
|
|
766
|
-
className: "w-full rounded-md bg-primary",
|
|
1522
|
+
className: "w-full rounded-md bg-primary transition-all",
|
|
767
1523
|
style: {
|
|
768
1524
|
height: `${Math.max(point.messageCount / maxMessages * 100, 8)}%`
|
|
769
1525
|
}
|
|
770
1526
|
}
|
|
771
1527
|
) }),
|
|
772
|
-
/* @__PURE__ */ (0,
|
|
773
|
-
/* @__PURE__ */ (0,
|
|
774
|
-
/* @__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: [
|
|
775
1531
|
formatNumber(point.messageCount),
|
|
776
1532
|
" msg"
|
|
777
1533
|
] })
|
|
@@ -779,40 +1535,45 @@ function ActivityChart(props) {
|
|
|
779
1535
|
]
|
|
780
1536
|
},
|
|
781
1537
|
point.bucket
|
|
782
|
-
)) }) })
|
|
1538
|
+
)) }) });
|
|
783
1539
|
}
|
|
784
1540
|
function DataTable(props) {
|
|
785
|
-
return /* @__PURE__ */ (0,
|
|
786
|
-
/* @__PURE__ */ (0,
|
|
787
|
-
/* @__PURE__ */ (0,
|
|
788
|
-
/* @__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)(
|
|
789
1545
|
Input,
|
|
790
1546
|
{
|
|
791
|
-
className: "w-full max-w-44
|
|
1547
|
+
className: "h-8 w-full max-w-44",
|
|
792
1548
|
onChange: (event) => props.setSearchValue(event.target.value),
|
|
793
1549
|
placeholder: props.searchPlaceholder,
|
|
794
1550
|
value: props.searchValue
|
|
795
1551
|
}
|
|
796
1552
|
)
|
|
797
1553
|
] }),
|
|
798
|
-
props.rows.length === 0 ? /* @__PURE__ */ (0,
|
|
799
|
-
] })
|
|
1554
|
+
props.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-sm text-muted-foreground", children: "No results" }) : props.children
|
|
1555
|
+
] });
|
|
800
1556
|
}
|
|
801
1557
|
function ThreadsTable({
|
|
802
1558
|
rows,
|
|
803
|
-
labels
|
|
1559
|
+
labels,
|
|
1560
|
+
onThreadClick
|
|
804
1561
|
}) {
|
|
805
|
-
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)(
|
|
806
1563
|
"div",
|
|
807
1564
|
{
|
|
808
|
-
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),
|
|
809
1570
|
children: [
|
|
810
|
-
/* @__PURE__ */ (0,
|
|
811
|
-
/* @__PURE__ */ (0,
|
|
812
|
-
/* @__PURE__ */ (0,
|
|
813
|
-
/* @__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" })
|
|
814
1575
|
] }),
|
|
815
|
-
/* @__PURE__ */ (0,
|
|
1576
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
816
1577
|
Badge,
|
|
817
1578
|
{
|
|
818
1579
|
variant: thread.status === "archived" ? "secondary" : "default",
|
|
@@ -820,16 +1581,16 @@ function ThreadsTable({
|
|
|
820
1581
|
}
|
|
821
1582
|
)
|
|
822
1583
|
] }),
|
|
823
|
-
/* @__PURE__ */ (0,
|
|
824
|
-
/* @__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: [
|
|
825
1586
|
formatNumber(thread.messageCount),
|
|
826
1587
|
" messages"
|
|
827
1588
|
] }),
|
|
828
|
-
/* @__PURE__ */ (0,
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
829
1590
|
thread.participantIds.length,
|
|
830
1591
|
" participants"
|
|
831
1592
|
] }),
|
|
832
|
-
/* @__PURE__ */ (0,
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: formatDate(thread.lastActivityAt) })
|
|
833
1594
|
] })
|
|
834
1595
|
]
|
|
835
1596
|
},
|
|
@@ -840,28 +1601,28 @@ function ParticipantsTable({
|
|
|
840
1601
|
rows,
|
|
841
1602
|
labels
|
|
842
1603
|
}) {
|
|
843
|
-
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)(
|
|
844
1605
|
"div",
|
|
845
1606
|
{
|
|
846
1607
|
className: "rounded-lg border bg-muted/50 p-4",
|
|
847
1608
|
children: [
|
|
848
|
-
/* @__PURE__ */ (0,
|
|
849
|
-
/* @__PURE__ */ (0,
|
|
850
|
-
/* @__PURE__ */ (0,
|
|
851
|
-
/* @__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 })
|
|
852
1613
|
] }),
|
|
853
|
-
/* @__PURE__ */ (0,
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Badge, { variant: "outline", children: participant.isGlobal ? labels.scopeGlobal : labels.scopeScoped })
|
|
854
1615
|
] }),
|
|
855
|
-
/* @__PURE__ */ (0,
|
|
856
|
-
/* @__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: [
|
|
857
1618
|
formatNumber(participant.messageCount),
|
|
858
1619
|
" messages"
|
|
859
1620
|
] }),
|
|
860
|
-
/* @__PURE__ */ (0,
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
861
1622
|
formatNumber(participant.threadCount),
|
|
862
1623
|
" threads"
|
|
863
1624
|
] }),
|
|
864
|
-
/* @__PURE__ */ (0,
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: formatDate(participant.lastActivityAt) })
|
|
865
1626
|
] })
|
|
866
1627
|
]
|
|
867
1628
|
},
|
|
@@ -872,32 +1633,32 @@ function AgentsTable({
|
|
|
872
1633
|
rows,
|
|
873
1634
|
labels
|
|
874
1635
|
}) {
|
|
875
|
-
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)(
|
|
876
1637
|
"div",
|
|
877
1638
|
{
|
|
878
1639
|
className: "rounded-lg border bg-muted/50 p-4",
|
|
879
1640
|
children: [
|
|
880
|
-
/* @__PURE__ */ (0,
|
|
881
|
-
/* @__PURE__ */ (0,
|
|
882
|
-
/* @__PURE__ */ (0,
|
|
883
|
-
/* @__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 })
|
|
884
1645
|
] }),
|
|
885
|
-
/* @__PURE__ */ (0,
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Badge, { variant: "outline", children: agent.isConfigured ? labels.configured : labels.unconfigured })
|
|
886
1647
|
] }),
|
|
887
|
-
/* @__PURE__ */ (0,
|
|
888
|
-
/* @__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: [
|
|
889
1650
|
formatNumber(agent.messageCount),
|
|
890
1651
|
" messages"
|
|
891
1652
|
] }),
|
|
892
|
-
/* @__PURE__ */ (0,
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
893
1654
|
formatNumber(agent.llmCallCount),
|
|
894
1655
|
" LLM calls"
|
|
895
1656
|
] }),
|
|
896
|
-
/* @__PURE__ */ (0,
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
897
1658
|
formatNumber(agent.toolCallMessageCount),
|
|
898
1659
|
" tool calls"
|
|
899
1660
|
] }),
|
|
900
|
-
/* @__PURE__ */ (0,
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
|
|
901
1662
|
formatNumber(agent.totalTokens),
|
|
902
1663
|
" tokens"
|
|
903
1664
|
] })
|
|
@@ -933,6 +1694,476 @@ function formatDate(value) {
|
|
|
933
1694
|
function formatNumber(value) {
|
|
934
1695
|
return new Intl.NumberFormat().format(value);
|
|
935
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
|
+
};
|
|
936
2167
|
// Annotate the CommonJS export names for ESM import in node:
|
|
937
2168
|
0 && (module.exports = {
|
|
938
2169
|
CopilotzAdmin,
|