@arbidocs/react 0.3.100 → 0.3.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,14 +1,47 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
3
+ var React = require('react');
4
4
  var browser = require('@arbidocs/sdk/browser');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var reactQuery = require('@tanstack/react-query');
7
+ var reactDom = require('react-dom');
8
+ var clsx = require('clsx');
9
+ var tailwindMerge = require('tailwind-merge');
10
+ var AvatarPrimitive = require('@radix-ui/react-avatar');
11
+ var classVarianceAuthority = require('class-variance-authority');
12
+ var reactSlot = require('@radix-ui/react-slot');
13
+ var HoverCardPrimitive = require('@radix-ui/react-hover-card');
14
+ var lucideReact = require('lucide-react');
15
+ var agGridReact = require('ag-grid-react');
16
+ var agGridCommunity = require('ag-grid-community');
17
+ var zustand = require('zustand');
18
+
19
+ function _interopNamespace(e) {
20
+ if (e && e.__esModule) return e;
21
+ var n = Object.create(null);
22
+ if (e) {
23
+ Object.keys(e).forEach(function (k) {
24
+ if (k !== 'default') {
25
+ var d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.defineProperty(n, k, d.get ? d : {
27
+ enumerable: true,
28
+ get: function () { return e[k]; }
29
+ });
30
+ }
31
+ });
32
+ }
33
+ n.default = e;
34
+ return Object.freeze(n);
35
+ }
36
+
37
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
38
+ var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
39
+ var HoverCardPrimitive__namespace = /*#__PURE__*/_interopNamespace(HoverCardPrimitive);
7
40
 
8
41
  // src/ArbiProvider.tsx
9
- var ArbiContext = react.createContext(null);
42
+ var ArbiContext = React.createContext(null);
10
43
  function ArbiProvider({ children, ...options }) {
11
- const arbi = react.useMemo(
44
+ const arbi = React.useMemo(
12
45
  () => new browser.Arbi(options),
13
46
  // Stable on url + deploymentDomain — re-creating the instance on every render would be wrong
14
47
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -340,7 +373,7 @@ function agentStatusStyle(theme) {
340
373
  };
341
374
  }
342
375
  function useArbi() {
343
- const arbi = react.useContext(ArbiContext);
376
+ const arbi = React.useContext(ArbiContext);
344
377
  if (!arbi) {
345
378
  throw new Error("useArbi() must be used within an <ArbiProvider>");
346
379
  }
@@ -348,16 +381,16 @@ function useArbi() {
348
381
  }
349
382
  function AuthScreen({ theme, labels, onLogin }) {
350
383
  const arbi = useArbi();
351
- const [mode, setMode] = react.useState("login");
352
- const [step, setStep] = react.useState("email");
353
- const [email, setEmail] = react.useState("");
354
- const [password, setPassword] = react.useState("");
355
- const [confirmPw, setConfirmPw] = react.useState("");
356
- const [code, setCode] = react.useState("");
357
- const [firstName, setFirstName] = react.useState("");
358
- const [lastName, setLastName] = react.useState("");
359
- const [loading, setLoading] = react.useState(false);
360
- const [error, setError] = react.useState("");
384
+ const [mode, setMode] = React.useState("login");
385
+ const [step, setStep] = React.useState("email");
386
+ const [email, setEmail] = React.useState("");
387
+ const [password, setPassword] = React.useState("");
388
+ const [confirmPw, setConfirmPw] = React.useState("");
389
+ const [code, setCode] = React.useState("");
390
+ const [firstName, setFirstName] = React.useState("");
391
+ const [lastName, setLastName] = React.useState("");
392
+ const [loading, setLoading] = React.useState(false);
393
+ const [error, setError] = React.useState("");
361
394
  const resetForm = () => {
362
395
  setPassword("");
363
396
  setConfirmPw("");
@@ -591,7 +624,10 @@ var arbiQueryKeys = {
591
624
  tags: (workspaceId) => ["arbi", "tags", workspaceId],
592
625
  agents: () => ["arbi", "agents"],
593
626
  sessions: () => ["arbi", "sessions"],
594
- health: () => ["arbi", "health"]
627
+ health: () => ["arbi", "health"],
628
+ tasks: () => ["arbi", "tasks"],
629
+ memories: (workspaceId) => ["arbi", "memories", workspaceId],
630
+ configs: () => ["arbi", "configs"]
595
631
  };
596
632
  function useWorkspaces(options) {
597
633
  const arbi = useArbi();
@@ -661,14 +697,38 @@ function useHealth(options) {
661
697
  enabled: options?.enabled
662
698
  });
663
699
  }
700
+ function useTasks(options) {
701
+ const arbi = useArbi();
702
+ return reactQuery.useQuery({
703
+ queryKey: arbiQueryKeys.tasks(),
704
+ queryFn: () => arbi.tasks.list(),
705
+ enabled: options?.enabled ?? arbi.isLoggedIn
706
+ });
707
+ }
708
+ function useMemories(workspaceId, options) {
709
+ const arbi = useArbi();
710
+ return reactQuery.useQuery({
711
+ queryKey: arbiQueryKeys.memories(workspaceId ?? ""),
712
+ queryFn: () => arbi.memory.list({ pinnedOnly: options?.pinnedOnly }),
713
+ enabled: (options?.enabled ?? true) && !!workspaceId && arbi.hasWorkspace
714
+ });
715
+ }
716
+ function useConfigs(options) {
717
+ const arbi = useArbi();
718
+ return reactQuery.useQuery({
719
+ queryKey: arbiQueryKeys.configs(),
720
+ queryFn: () => arbi.agentConfig.list(),
721
+ enabled: options?.enabled ?? arbi.isLoggedIn
722
+ });
723
+ }
664
724
  function WorkspaceScreen({ theme, labels, onSelect }) {
665
725
  const arbi = useArbi();
666
726
  const { data: workspaces, isLoading } = useWorkspaces();
667
- const [mode, setMode] = react.useState("select");
668
- const [selected, setSelected] = react.useState("");
669
- const [newName, setNewName] = react.useState("");
670
- const [loading, setLoading] = react.useState(false);
671
- const [error, setError] = react.useState("");
727
+ const [mode, setMode] = React.useState("select");
728
+ const [selected, setSelected] = React.useState("");
729
+ const [newName, setNewName] = React.useState("");
730
+ const [loading, setLoading] = React.useState(false);
731
+ const [error, setError] = React.useState("");
672
732
  if (isLoading) {
673
733
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: loadingContainerStyle(), children: "Loading workspaces..." });
674
734
  }
@@ -823,7 +883,7 @@ function renderWithCitations(text, theme, onCiteClick) {
823
883
  return nodes.length > 0 ? nodes : [text];
824
884
  }
825
885
  function MessageBubble({ message, theme }) {
826
- const [expandedCite, setExpandedCite] = react.useState(null);
886
+ const [expandedCite, setExpandedCite] = React.useState(null);
827
887
  const hasCitations = message.role === "assistant" && message.metadata && CITE_RE.test(message.text);
828
888
  CITE_RE.lastIndex = 0;
829
889
  const resolved = hasCitations ? browser.resolveCitations(message.metadata) : [];
@@ -903,22 +963,22 @@ function ChatView({ workspaceId, theme, labels }) {
903
963
  const arbi = useArbi();
904
964
  const { data: docs, refetch: refetchDocs } = useDocuments(workspaceId);
905
965
  const mutation = useAssistantQuery();
906
- const [messages, setMessages] = react.useState([]);
907
- const [input, setInput] = react.useState("");
908
- const [streaming, setStreaming] = react.useState("");
909
- const [agentStatus, setAgentStatus] = react.useState("");
910
- const [selectedDocs, setSelectedDocs] = react.useState([]);
911
- const [docsExpanded, setDocsExpanded] = react.useState(false);
912
- const [previousResponseId, setPreviousResponseId] = react.useState(null);
913
- const [uploading, setUploading] = react.useState(false);
914
- const messagesEndRef = react.useRef(null);
915
- const fileInputRef = react.useRef(null);
916
- react.useEffect(() => {
966
+ const [messages, setMessages] = React.useState([]);
967
+ const [input, setInput] = React.useState("");
968
+ const [streaming, setStreaming] = React.useState("");
969
+ const [agentStatus, setAgentStatus] = React.useState("");
970
+ const [selectedDocs, setSelectedDocs] = React.useState([]);
971
+ const [docsExpanded, setDocsExpanded] = React.useState(false);
972
+ const [previousResponseId, setPreviousResponseId] = React.useState(null);
973
+ const [uploading, setUploading] = React.useState(false);
974
+ const messagesEndRef = React.useRef(null);
975
+ const fileInputRef = React.useRef(null);
976
+ React.useEffect(() => {
917
977
  if (docs && docs.length > 0 && selectedDocs.length === 0) {
918
978
  setSelectedDocs(docs.map((d) => d.external_id));
919
979
  }
920
980
  }, [docs, selectedDocs.length]);
921
- react.useEffect(() => {
981
+ React.useEffect(() => {
922
982
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
923
983
  }, [messages, streaming, agentStatus]);
924
984
  const toggleDoc = (docId) => {
@@ -926,7 +986,7 @@ function ChatView({ workspaceId, theme, labels }) {
926
986
  (prev) => prev.includes(docId) ? prev.filter((id) => id !== docId) : [...prev, docId]
927
987
  );
928
988
  };
929
- const handleUpload = react.useCallback(
989
+ const handleUpload = React.useCallback(
930
990
  async (e) => {
931
991
  const files = e.target.files;
932
992
  if (!files || files.length === 0) return;
@@ -947,7 +1007,7 @@ function ChatView({ workspaceId, theme, labels }) {
947
1007
  },
948
1008
  [arbi, refetchDocs]
949
1009
  );
950
- const handleSubmit = react.useCallback(
1010
+ const handleSubmit = React.useCallback(
951
1011
  (e) => {
952
1012
  e.preventDefault();
953
1013
  const question = input.trim();
@@ -1078,25 +1138,30 @@ function ChatView({ workspaceId, theme, labels }) {
1078
1138
  }
1079
1139
  function ChatWidget({ theme, labels, initialWorkspaceId, width, height }) {
1080
1140
  const arbi = useArbi();
1081
- const [screen, setScreen] = react.useState("auth");
1082
- const [workspaceId, setWorkspaceId] = react.useState(initialWorkspaceId);
1083
- const handleLogin = react.useCallback(async () => {
1141
+ const [screen, setScreen] = React.useState("auth");
1142
+ const [workspaceId, setWorkspaceId] = React.useState(initialWorkspaceId);
1143
+ const resolveWorkspace = React.useCallback(async () => {
1084
1144
  if (initialWorkspaceId) {
1085
1145
  try {
1086
1146
  await arbi.selectWorkspace(initialWorkspaceId);
1087
1147
  setScreen("chat");
1148
+ return;
1088
1149
  } catch {
1089
1150
  setScreen("workspace");
1151
+ return;
1090
1152
  }
1091
- } else {
1092
- setScreen("workspace");
1093
1153
  }
1154
+ setScreen("workspace");
1094
1155
  }, [arbi, initialWorkspaceId]);
1095
- const handleWorkspaceSelect = react.useCallback((id) => {
1156
+ const handleLogin = React.useCallback(() => resolveWorkspace(), [resolveWorkspace]);
1157
+ React.useEffect(() => {
1158
+ if (arbi.isLoggedIn) void resolveWorkspace();
1159
+ }, [arbi, resolveWorkspace]);
1160
+ const handleWorkspaceSelect = React.useCallback((id) => {
1096
1161
  setWorkspaceId(id);
1097
1162
  setScreen("chat");
1098
1163
  }, []);
1099
- const handleChangeWorkspace = react.useCallback(() => {
1164
+ const handleChangeWorkspace = React.useCallback(() => {
1100
1165
  setScreen("workspace");
1101
1166
  }, []);
1102
1167
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle(theme, width, height), children: [
@@ -1125,6 +1190,26 @@ function ChatWidget({ theme, labels, initialWorkspaceId, width, height }) {
1125
1190
  ] })
1126
1191
  ] });
1127
1192
  }
1193
+ function ArbiChatPanel({
1194
+ workspaceId,
1195
+ theme: themeOverrides,
1196
+ labels: labelOverrides,
1197
+ width = "100%",
1198
+ height = "100%"
1199
+ }) {
1200
+ const theme = React.useMemo(() => getTheme(themeOverrides), [themeOverrides]);
1201
+ const labels = React.useMemo(() => getLabels(labelOverrides), [labelOverrides]);
1202
+ return /* @__PURE__ */ jsxRuntime.jsx(
1203
+ ChatWidget,
1204
+ {
1205
+ theme,
1206
+ labels,
1207
+ initialWorkspaceId: workspaceId,
1208
+ width,
1209
+ height
1210
+ }
1211
+ );
1212
+ }
1128
1213
  function ArbiChat({
1129
1214
  url,
1130
1215
  workspaceId,
@@ -1133,7 +1218,7 @@ function ArbiChat({
1133
1218
  width = "400px",
1134
1219
  height = "600px"
1135
1220
  }) {
1136
- const queryClient = react.useMemo(
1221
+ const queryClient = React.useMemo(
1137
1222
  () => new reactQuery.QueryClient({
1138
1223
  defaultOptions: {
1139
1224
  queries: { retry: 1, refetchOnWindowFocus: false },
@@ -1142,19 +1227,1262 @@ function ArbiChat({
1142
1227
  }),
1143
1228
  []
1144
1229
  );
1145
- const theme = react.useMemo(() => getTheme(themeOverrides), [themeOverrides]);
1146
- const labels = react.useMemo(() => getLabels(labelOverrides), [labelOverrides]);
1147
1230
  return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(ArbiProvider, { url, children: /* @__PURE__ */ jsxRuntime.jsx(
1148
- ChatWidget,
1231
+ ArbiChatPanel,
1149
1232
  {
1150
- theme,
1151
- labels,
1152
- initialWorkspaceId: workspaceId,
1233
+ workspaceId,
1234
+ theme: themeOverrides,
1235
+ labels: labelOverrides,
1153
1236
  width,
1154
1237
  height
1155
1238
  }
1156
1239
  ) }) });
1157
1240
  }
1241
+ function cn(...inputs) {
1242
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
1243
+ }
1244
+ var TooltipContext = React__namespace.createContext(null);
1245
+ var TooltipProvider = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1246
+ function Tooltip({ children, delayDuration = 300 }) {
1247
+ const [open, setOpen] = React__namespace.useState(false);
1248
+ const triggerRef = React__namespace.useRef(null);
1249
+ const timer = React__namespace.useRef(null);
1250
+ const contentId = React__namespace.useId();
1251
+ const clearTimer = () => {
1252
+ if (timer.current) {
1253
+ clearTimeout(timer.current);
1254
+ timer.current = null;
1255
+ }
1256
+ };
1257
+ const show = React__namespace.useCallback(() => {
1258
+ clearTimer();
1259
+ timer.current = setTimeout(() => setOpen(true), delayDuration);
1260
+ }, [delayDuration]);
1261
+ const hide = React__namespace.useCallback(() => {
1262
+ clearTimer();
1263
+ setOpen(false);
1264
+ }, []);
1265
+ const setTrigger = React__namespace.useCallback((el) => {
1266
+ triggerRef.current = el;
1267
+ }, []);
1268
+ React__namespace.useEffect(() => () => clearTimer(), []);
1269
+ const value = React__namespace.useMemo(
1270
+ () => ({ open, show, hide, setTrigger, triggerRef, contentId }),
1271
+ [open, show, hide, setTrigger, contentId]
1272
+ );
1273
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipContext.Provider, { value, children });
1274
+ }
1275
+ function TooltipTrigger({ asChild, children, ...props }) {
1276
+ const ctx = React__namespace.useContext(TooltipContext);
1277
+ if (!ctx) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1278
+ const triggerHandlers = {
1279
+ onPointerEnter: (e) => {
1280
+ props.onPointerEnter?.(e);
1281
+ ctx.show();
1282
+ },
1283
+ onPointerLeave: (e) => {
1284
+ props.onPointerLeave?.(e);
1285
+ ctx.hide();
1286
+ },
1287
+ onFocus: (e) => {
1288
+ props.onFocus?.(e);
1289
+ ctx.show();
1290
+ },
1291
+ onBlur: (e) => {
1292
+ props.onBlur?.(e);
1293
+ ctx.hide();
1294
+ },
1295
+ "aria-describedby": ctx.open ? ctx.contentId : void 0,
1296
+ "data-state": ctx.open ? "open" : "closed"
1297
+ };
1298
+ if (asChild && React__namespace.isValidElement(children)) {
1299
+ const child = children;
1300
+ return React__namespace.cloneElement(child, {
1301
+ ...props,
1302
+ ...triggerHandlers,
1303
+ ref: ctx.setTrigger
1304
+ });
1305
+ }
1306
+ return /* @__PURE__ */ jsxRuntime.jsx(
1307
+ "button",
1308
+ {
1309
+ type: "button",
1310
+ ...props,
1311
+ ...triggerHandlers,
1312
+ ref: ctx.setTrigger,
1313
+ children
1314
+ }
1315
+ );
1316
+ }
1317
+ var TRANSFORM_BY_SIDE = {
1318
+ top: "translate(-50%, -100%)",
1319
+ bottom: "translate(-50%, 0)",
1320
+ left: "translate(-100%, -50%)",
1321
+ right: "translate(0, -50%)"
1322
+ };
1323
+ var TooltipContent = React__namespace.forwardRef(
1324
+ ({ className, side = "top", sideOffset = 4, style, ...props }, ref) => {
1325
+ const ctx = React__namespace.useContext(TooltipContext);
1326
+ const innerRef = React__namespace.useRef(null);
1327
+ const [coords, setCoords] = React__namespace.useState(null);
1328
+ React__namespace.useLayoutEffect(() => {
1329
+ if (!ctx?.open || !ctx.triggerRef.current) {
1330
+ setCoords(null);
1331
+ return;
1332
+ }
1333
+ const r = ctx.triggerRef.current.getBoundingClientRect();
1334
+ const c = innerRef.current?.getBoundingClientRect();
1335
+ const ch = c?.height ?? 0;
1336
+ const cw = c?.width ?? 0;
1337
+ const vh = window.innerHeight;
1338
+ const vw = window.innerWidth;
1339
+ let s = side;
1340
+ if (s === "top" && r.top - sideOffset - ch < 0) s = "bottom";
1341
+ else if (s === "bottom" && r.bottom + sideOffset + ch > vh) s = "top";
1342
+ else if (s === "left" && r.left - sideOffset - cw < 0) s = "right";
1343
+ else if (s === "right" && r.right + sideOffset + cw > vw) s = "left";
1344
+ setCoords({
1345
+ top: s === "top" ? r.top - sideOffset : s === "bottom" ? r.bottom + sideOffset : r.top + r.height / 2,
1346
+ left: s === "left" ? r.left - sideOffset : s === "right" ? r.right + sideOffset : r.left + r.width / 2,
1347
+ transform: TRANSFORM_BY_SIDE[s]
1348
+ });
1349
+ }, [ctx?.open, side, sideOffset, ctx?.triggerRef]);
1350
+ if (!ctx?.open) return null;
1351
+ const setRefs = (node) => {
1352
+ innerRef.current = node;
1353
+ if (typeof ref === "function") ref(node);
1354
+ else if (ref) ref.current = node;
1355
+ };
1356
+ return reactDom.createPortal(
1357
+ /* @__PURE__ */ jsxRuntime.jsx(
1358
+ "div",
1359
+ {
1360
+ ref: setRefs,
1361
+ id: ctx.contentId,
1362
+ role: "tooltip",
1363
+ className: cn("tooltip-content pointer-events-none", className),
1364
+ style: {
1365
+ position: "fixed",
1366
+ top: coords?.top ?? -9999,
1367
+ left: coords?.left ?? -9999,
1368
+ transform: coords?.transform ?? TRANSFORM_BY_SIDE[side],
1369
+ opacity: coords ? void 0 : 0,
1370
+ zIndex: 9999,
1371
+ ...style
1372
+ },
1373
+ ...props
1374
+ }
1375
+ ),
1376
+ document.body
1377
+ );
1378
+ }
1379
+ );
1380
+ TooltipContent.displayName = "TooltipContent";
1381
+ var Avatar = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1382
+ AvatarPrimitive__namespace.Root,
1383
+ {
1384
+ ref,
1385
+ className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
1386
+ ...props
1387
+ }
1388
+ ));
1389
+ Avatar.displayName = AvatarPrimitive__namespace.Root.displayName;
1390
+ var AvatarImage = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1391
+ AvatarPrimitive__namespace.Image,
1392
+ {
1393
+ ref,
1394
+ className: cn("aspect-square h-full w-full", className),
1395
+ ...props
1396
+ }
1397
+ ));
1398
+ AvatarImage.displayName = AvatarPrimitive__namespace.Image.displayName;
1399
+ var AvatarFallback = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1400
+ AvatarPrimitive__namespace.Fallback,
1401
+ {
1402
+ ref,
1403
+ className: cn(
1404
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
1405
+ className
1406
+ ),
1407
+ ...props
1408
+ }
1409
+ ));
1410
+ AvatarFallback.displayName = AvatarPrimitive__namespace.Fallback.displayName;
1411
+ var badgeVariants = classVarianceAuthority.cva(
1412
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-sm font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
1413
+ {
1414
+ variants: {
1415
+ variant: {
1416
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
1417
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
1418
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
1419
+ outline: "text-foreground"
1420
+ }
1421
+ },
1422
+ defaultVariants: {
1423
+ variant: "default"
1424
+ }
1425
+ }
1426
+ );
1427
+ function Badge({ className, variant, ...props }) {
1428
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
1429
+ }
1430
+ var buttonVariants = classVarianceAuthority.cva(
1431
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1432
+ {
1433
+ variants: {
1434
+ variant: {
1435
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
1436
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
1437
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
1438
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
1439
+ ghost: "hover:bg-accent hover:text-accent-foreground",
1440
+ link: "text-primary underline-offset-4 hover:underline"
1441
+ },
1442
+ size: {
1443
+ default: "h-9 px-4 py-2",
1444
+ sm: "h-8 rounded-md px-3",
1445
+ lg: "h-10 rounded-md px-8",
1446
+ icon: "h-9 w-9"
1447
+ }
1448
+ },
1449
+ defaultVariants: {
1450
+ variant: "default",
1451
+ size: "default"
1452
+ }
1453
+ }
1454
+ );
1455
+ var Button = React__namespace.forwardRef(
1456
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
1457
+ const Comp = asChild ? reactSlot.Slot : "button";
1458
+ return /* @__PURE__ */ jsxRuntime.jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
1459
+ }
1460
+ );
1461
+ Button.displayName = "Button";
1462
+ var HoverCard = HoverCardPrimitive__namespace.Root;
1463
+ var HoverCardTrigger = HoverCardPrimitive__namespace.Trigger;
1464
+ var HoverCardContent = React__namespace.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(HoverCardPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1465
+ HoverCardPrimitive__namespace.Content,
1466
+ {
1467
+ ref,
1468
+ align,
1469
+ sideOffset,
1470
+ className: cn(
1471
+ "z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 origin-[--radix-hover-card-content-transform-origin]",
1472
+ className
1473
+ ),
1474
+ ...props
1475
+ }
1476
+ ) }));
1477
+ HoverCardContent.displayName = HoverCardPrimitive__namespace.Content.displayName;
1478
+
1479
+ // src/icons/colors.ts
1480
+ var NEUTRAL_GRAY = "#64748b";
1481
+ var FILE_TYPE_COLORS = {
1482
+ pdf: "#ef4444",
1483
+ // red
1484
+ img: "#8b5cf6",
1485
+ // violet-500 (images)
1486
+ vid: "#10b981",
1487
+ // emerald-500 (video)
1488
+ aud: "#f59e0b",
1489
+ // amber-500 (audio)
1490
+ eml: "#0d9488",
1491
+ // teal-600 (email)
1492
+ generic: NEUTRAL_GRAY,
1493
+ // gray (unknown)
1494
+ white: "#ffffff"
1495
+ // for strokes/text on colored backgrounds
1496
+ };
1497
+ var PdfIcon = ({ size = 16, className = "" }) => {
1498
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1499
+ "svg",
1500
+ {
1501
+ width: size,
1502
+ height: size,
1503
+ viewBox: "0 0 24 24",
1504
+ fill: "none",
1505
+ xmlns: "http://www.w3.org/2000/svg",
1506
+ className,
1507
+ children: [
1508
+ /* @__PURE__ */ jsxRuntime.jsx(
1509
+ "path",
1510
+ {
1511
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1512
+ fill: FILE_TYPE_COLORS.pdf,
1513
+ stroke: FILE_TYPE_COLORS.pdf,
1514
+ strokeWidth: "1",
1515
+ strokeLinecap: "round",
1516
+ strokeLinejoin: "round"
1517
+ }
1518
+ ),
1519
+ /* @__PURE__ */ jsxRuntime.jsx(
1520
+ "path",
1521
+ {
1522
+ d: "M14 2v6h6",
1523
+ fill: "none",
1524
+ stroke: FILE_TYPE_COLORS.white,
1525
+ strokeWidth: "1",
1526
+ strokeLinecap: "round",
1527
+ strokeLinejoin: "round"
1528
+ }
1529
+ ),
1530
+ /* @__PURE__ */ jsxRuntime.jsx(
1531
+ "text",
1532
+ {
1533
+ x: "12",
1534
+ y: "16",
1535
+ fontSize: "6",
1536
+ fill: "white",
1537
+ textAnchor: "middle",
1538
+ fontWeight: "bold",
1539
+ fontFamily: "Arial, sans-serif",
1540
+ children: "PDF"
1541
+ }
1542
+ )
1543
+ ]
1544
+ }
1545
+ );
1546
+ };
1547
+ var AudIcon = ({ size = 16, className = "" }) => {
1548
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1549
+ "svg",
1550
+ {
1551
+ width: size,
1552
+ height: size,
1553
+ viewBox: "0 0 24 24",
1554
+ fill: "none",
1555
+ xmlns: "http://www.w3.org/2000/svg",
1556
+ className,
1557
+ children: [
1558
+ /* @__PURE__ */ jsxRuntime.jsx(
1559
+ "path",
1560
+ {
1561
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1562
+ fill: FILE_TYPE_COLORS.aud,
1563
+ stroke: FILE_TYPE_COLORS.aud,
1564
+ strokeWidth: "1",
1565
+ strokeLinecap: "round",
1566
+ strokeLinejoin: "round"
1567
+ }
1568
+ ),
1569
+ /* @__PURE__ */ jsxRuntime.jsx(
1570
+ "path",
1571
+ {
1572
+ d: "M14 2v6h6",
1573
+ fill: "none",
1574
+ stroke: FILE_TYPE_COLORS.white,
1575
+ strokeWidth: "1",
1576
+ strokeLinecap: "round",
1577
+ strokeLinejoin: "round"
1578
+ }
1579
+ ),
1580
+ /* @__PURE__ */ jsxRuntime.jsx(
1581
+ "text",
1582
+ {
1583
+ x: "12",
1584
+ y: "16",
1585
+ fontSize: "6",
1586
+ fill: "white",
1587
+ textAnchor: "middle",
1588
+ fontWeight: "bold",
1589
+ fontFamily: "Arial, sans-serif",
1590
+ children: "AUD"
1591
+ }
1592
+ )
1593
+ ]
1594
+ }
1595
+ );
1596
+ };
1597
+ var ImgIcon = ({ size = 16, className = "" }) => {
1598
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1599
+ "svg",
1600
+ {
1601
+ width: size,
1602
+ height: size,
1603
+ viewBox: "0 0 24 24",
1604
+ fill: "none",
1605
+ xmlns: "http://www.w3.org/2000/svg",
1606
+ className,
1607
+ children: [
1608
+ /* @__PURE__ */ jsxRuntime.jsx(
1609
+ "path",
1610
+ {
1611
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1612
+ fill: FILE_TYPE_COLORS.img,
1613
+ stroke: FILE_TYPE_COLORS.img,
1614
+ strokeWidth: "1",
1615
+ strokeLinecap: "round",
1616
+ strokeLinejoin: "round"
1617
+ }
1618
+ ),
1619
+ /* @__PURE__ */ jsxRuntime.jsx(
1620
+ "path",
1621
+ {
1622
+ d: "M14 2v6h6",
1623
+ fill: "none",
1624
+ stroke: FILE_TYPE_COLORS.white,
1625
+ strokeWidth: "1",
1626
+ strokeLinecap: "round",
1627
+ strokeLinejoin: "round"
1628
+ }
1629
+ ),
1630
+ /* @__PURE__ */ jsxRuntime.jsx(
1631
+ "text",
1632
+ {
1633
+ x: "12",
1634
+ y: "16",
1635
+ fontSize: "6",
1636
+ fill: "white",
1637
+ textAnchor: "middle",
1638
+ fontWeight: "bold",
1639
+ fontFamily: "Arial, sans-serif",
1640
+ children: "IMG"
1641
+ }
1642
+ )
1643
+ ]
1644
+ }
1645
+ );
1646
+ };
1647
+ var VidIcon = ({ size = 16, className = "" }) => {
1648
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1649
+ "svg",
1650
+ {
1651
+ width: size,
1652
+ height: size,
1653
+ viewBox: "0 0 24 24",
1654
+ fill: "none",
1655
+ xmlns: "http://www.w3.org/2000/svg",
1656
+ className,
1657
+ children: [
1658
+ /* @__PURE__ */ jsxRuntime.jsx(
1659
+ "path",
1660
+ {
1661
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1662
+ fill: FILE_TYPE_COLORS.vid,
1663
+ stroke: FILE_TYPE_COLORS.vid,
1664
+ strokeWidth: "1",
1665
+ strokeLinecap: "round",
1666
+ strokeLinejoin: "round"
1667
+ }
1668
+ ),
1669
+ /* @__PURE__ */ jsxRuntime.jsx(
1670
+ "path",
1671
+ {
1672
+ d: "M14 2v6h6",
1673
+ fill: "none",
1674
+ stroke: FILE_TYPE_COLORS.white,
1675
+ strokeWidth: "1",
1676
+ strokeLinecap: "round",
1677
+ strokeLinejoin: "round"
1678
+ }
1679
+ ),
1680
+ /* @__PURE__ */ jsxRuntime.jsx(
1681
+ "text",
1682
+ {
1683
+ x: "12",
1684
+ y: "16",
1685
+ fontSize: "6",
1686
+ fill: "white",
1687
+ textAnchor: "middle",
1688
+ fontWeight: "bold",
1689
+ fontFamily: "Arial, sans-serif",
1690
+ children: "VID"
1691
+ }
1692
+ )
1693
+ ]
1694
+ }
1695
+ );
1696
+ };
1697
+ var EmlIcon = ({ size = 16, className = "" }) => {
1698
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1699
+ "svg",
1700
+ {
1701
+ width: size,
1702
+ height: size,
1703
+ viewBox: "0 0 24 24",
1704
+ fill: "none",
1705
+ xmlns: "http://www.w3.org/2000/svg",
1706
+ className,
1707
+ children: [
1708
+ /* @__PURE__ */ jsxRuntime.jsx(
1709
+ "path",
1710
+ {
1711
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1712
+ fill: FILE_TYPE_COLORS.eml,
1713
+ stroke: FILE_TYPE_COLORS.eml,
1714
+ strokeWidth: "1",
1715
+ strokeLinecap: "round",
1716
+ strokeLinejoin: "round"
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ jsxRuntime.jsx(
1720
+ "path",
1721
+ {
1722
+ d: "M14 2v6h6",
1723
+ fill: "none",
1724
+ stroke: FILE_TYPE_COLORS.white,
1725
+ strokeWidth: "1",
1726
+ strokeLinecap: "round",
1727
+ strokeLinejoin: "round"
1728
+ }
1729
+ ),
1730
+ /* @__PURE__ */ jsxRuntime.jsx(
1731
+ "rect",
1732
+ {
1733
+ x: "7",
1734
+ y: "12",
1735
+ width: "10",
1736
+ height: "7",
1737
+ rx: "1",
1738
+ fill: "none",
1739
+ stroke: "white",
1740
+ strokeWidth: "1.2"
1741
+ }
1742
+ ),
1743
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 13l5 3 5-3", fill: "none", stroke: "white", strokeWidth: "1.2", strokeLinejoin: "round" })
1744
+ ]
1745
+ }
1746
+ );
1747
+ };
1748
+ var FileIcon = ({ size = 16, className = "" }) => {
1749
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1750
+ "svg",
1751
+ {
1752
+ width: size,
1753
+ height: size,
1754
+ viewBox: "0 0 24 24",
1755
+ fill: "none",
1756
+ xmlns: "http://www.w3.org/2000/svg",
1757
+ className,
1758
+ children: [
1759
+ /* @__PURE__ */ jsxRuntime.jsx(
1760
+ "path",
1761
+ {
1762
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1763
+ fill: FILE_TYPE_COLORS.generic,
1764
+ stroke: FILE_TYPE_COLORS.generic,
1765
+ strokeWidth: "1",
1766
+ strokeLinecap: "round",
1767
+ strokeLinejoin: "round"
1768
+ }
1769
+ ),
1770
+ /* @__PURE__ */ jsxRuntime.jsx(
1771
+ "path",
1772
+ {
1773
+ d: "M14 2v6h6",
1774
+ fill: "none",
1775
+ stroke: FILE_TYPE_COLORS.white,
1776
+ strokeWidth: "1",
1777
+ strokeLinecap: "round",
1778
+ strokeLinejoin: "round"
1779
+ }
1780
+ ),
1781
+ /* @__PURE__ */ jsxRuntime.jsx(
1782
+ "text",
1783
+ {
1784
+ x: "12",
1785
+ y: "17",
1786
+ fontSize: "10",
1787
+ fill: "white",
1788
+ textAnchor: "middle",
1789
+ fontWeight: "bold",
1790
+ fontFamily: "Arial, sans-serif",
1791
+ children: "?"
1792
+ }
1793
+ )
1794
+ ]
1795
+ }
1796
+ );
1797
+ };
1798
+ var EntityPill = React.forwardRef(function EntityPill2({
1799
+ icon,
1800
+ label,
1801
+ secondaryText,
1802
+ size = "sm",
1803
+ shape = "rounded",
1804
+ className,
1805
+ labelMaxWidth = "max-w-[320px]",
1806
+ fullWidth = false,
1807
+ highlight = false,
1808
+ onClick,
1809
+ onIconClick,
1810
+ onMoreClick,
1811
+ moreContent,
1812
+ href,
1813
+ disabled = false,
1814
+ tooltipContent,
1815
+ tooltipSide = "bottom",
1816
+ "data-testid": testId
1817
+ }, ref) {
1818
+ const shapeClass = shape === "pill" ? "rounded-full" : "rounded-md";
1819
+ const sizeClasses = size === "base" ? "gap-1.5 px-1.5 py-0.5" : "gap-1 px-1";
1820
+ const textSizeClass = size === "base" ? "text-base" : "text-sm";
1821
+ const baseClasses = cn(
1822
+ "group/pill items-center",
1823
+ fullWidth ? "flex w-full" : "inline-flex",
1824
+ sizeClasses,
1825
+ shapeClass,
1826
+ "bg-muted",
1827
+ "border border-border",
1828
+ "transition-all",
1829
+ className
1830
+ );
1831
+ const interactiveClasses = "cursor-pointer hover:bg-muted/80";
1832
+ const disabledClasses = "cursor-default opacity-60";
1833
+ const highlightClasses = "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground";
1834
+ const mainContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1835
+ onIconClick ? /* @__PURE__ */ jsxRuntime.jsx(
1836
+ "span",
1837
+ {
1838
+ role: "button",
1839
+ tabIndex: 0,
1840
+ className: "flex-shrink-0 cursor-pointer hover:opacity-70 transition-opacity",
1841
+ onClick: (e) => {
1842
+ e.stopPropagation();
1843
+ onIconClick(e);
1844
+ },
1845
+ children: icon
1846
+ }
1847
+ ) : icon,
1848
+ /* @__PURE__ */ jsxRuntime.jsx(
1849
+ "span",
1850
+ {
1851
+ className: cn(textSizeClass, "font-medium truncate leading-tight min-w-0", labelMaxWidth),
1852
+ children: label
1853
+ }
1854
+ ),
1855
+ secondaryText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground flex-shrink-0 leading-none", children: secondaryText })
1856
+ ] });
1857
+ const tooltipWrap = (content, tip, side = tooltipSide, triggerClassName, triggerProps) => /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
1858
+ /* @__PURE__ */ jsxRuntime.jsx(
1859
+ TooltipTrigger,
1860
+ {
1861
+ onFocusCapture: (e) => e.stopPropagation(),
1862
+ className: triggerClassName,
1863
+ ...triggerProps,
1864
+ children: content
1865
+ }
1866
+ ),
1867
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side, className: "p-2", children: tip })
1868
+ ] });
1869
+ const mainAreaClass = cn("inline-flex items-center gap-1", fullWidth && "min-w-0 flex-1");
1870
+ if (onMoreClick || moreContent) {
1871
+ let mainArea;
1872
+ if (tooltipContent) {
1873
+ mainArea = tooltipWrap(
1874
+ mainContent,
1875
+ tooltipContent,
1876
+ tooltipSide,
1877
+ cn(mainAreaClass, disabled && "opacity-60"),
1878
+ {
1879
+ type: "button",
1880
+ onClick: href ? onClick : disabled ? void 0 : onClick,
1881
+ disabled: disabled || void 0
1882
+ }
1883
+ );
1884
+ } else if (href) {
1885
+ mainArea = /* @__PURE__ */ jsxRuntime.jsx(
1886
+ "a",
1887
+ {
1888
+ href,
1889
+ target: "_blank",
1890
+ rel: "noopener noreferrer",
1891
+ className: mainAreaClass,
1892
+ onClick,
1893
+ children: mainContent
1894
+ }
1895
+ );
1896
+ } else if (onClick) {
1897
+ mainArea = /* @__PURE__ */ jsxRuntime.jsx(
1898
+ "button",
1899
+ {
1900
+ type: "button",
1901
+ onClick: disabled ? void 0 : onClick,
1902
+ disabled,
1903
+ className: cn("inline-flex items-center gap-1", disabled && "opacity-60"),
1904
+ children: mainContent
1905
+ }
1906
+ );
1907
+ } else {
1908
+ mainArea = /* @__PURE__ */ jsxRuntime.jsx("span", { className: mainAreaClass, children: mainContent });
1909
+ }
1910
+ const moreArea = moreContent ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 leading-none", children: moreContent }) : tooltipWrap(
1911
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { className: "w-3.5 h-3.5" }),
1912
+ "Click for more",
1913
+ tooltipSide,
1914
+ "flex-shrink-0 leading-none text-muted-foreground hover:text-foreground",
1915
+ {
1916
+ type: "button",
1917
+ onClick: (e) => {
1918
+ e.stopPropagation();
1919
+ onMoreClick?.(e);
1920
+ }
1921
+ }
1922
+ );
1923
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1924
+ "span",
1925
+ {
1926
+ ref,
1927
+ className: cn(
1928
+ baseClasses,
1929
+ (onClick || href) && !disabled && interactiveClasses,
1930
+ highlight && highlightClasses
1931
+ ),
1932
+ "data-testid": testId,
1933
+ children: [
1934
+ mainArea,
1935
+ moreArea
1936
+ ]
1937
+ }
1938
+ );
1939
+ }
1940
+ if (tooltipContent) {
1941
+ if (href) {
1942
+ return tooltipWrap(
1943
+ /* @__PURE__ */ jsxRuntime.jsx(
1944
+ "a",
1945
+ {
1946
+ href,
1947
+ target: "_blank",
1948
+ rel: "noopener noreferrer",
1949
+ className: mainAreaClass,
1950
+ onClick,
1951
+ children: mainContent
1952
+ }
1953
+ ),
1954
+ tooltipContent,
1955
+ tooltipSide,
1956
+ cn(baseClasses, interactiveClasses),
1957
+ { "data-testid": testId }
1958
+ );
1959
+ }
1960
+ return tooltipWrap(
1961
+ mainContent,
1962
+ tooltipContent,
1963
+ tooltipSide,
1964
+ cn(
1965
+ baseClasses,
1966
+ onClick && !disabled ? interactiveClasses : "",
1967
+ disabled ? disabledClasses : "",
1968
+ highlight && highlightClasses
1969
+ ),
1970
+ {
1971
+ type: "button",
1972
+ ref,
1973
+ onClick: onClick && !disabled ? onClick : void 0,
1974
+ disabled: disabled || void 0,
1975
+ "data-testid": testId
1976
+ }
1977
+ );
1978
+ }
1979
+ if (href) {
1980
+ return /* @__PURE__ */ jsxRuntime.jsx(
1981
+ "a",
1982
+ {
1983
+ ref,
1984
+ href,
1985
+ target: "_blank",
1986
+ rel: "noopener noreferrer",
1987
+ className: cn(baseClasses, interactiveClasses),
1988
+ "data-testid": testId,
1989
+ onClick,
1990
+ children: mainContent
1991
+ }
1992
+ );
1993
+ }
1994
+ if (onClick) {
1995
+ return /* @__PURE__ */ jsxRuntime.jsx(
1996
+ "button",
1997
+ {
1998
+ ref,
1999
+ type: "button",
2000
+ onClick: disabled ? void 0 : onClick,
2001
+ disabled,
2002
+ className: cn(
2003
+ baseClasses,
2004
+ disabled ? disabledClasses : interactiveClasses,
2005
+ highlight && highlightClasses
2006
+ ),
2007
+ "data-testid": testId,
2008
+ children: mainContent
2009
+ }
2010
+ );
2011
+ }
2012
+ return /* @__PURE__ */ jsxRuntime.jsx(
2013
+ "span",
2014
+ {
2015
+ ref,
2016
+ className: cn(baseClasses, highlight && highlightClasses),
2017
+ "data-testid": testId,
2018
+ children: mainContent
2019
+ }
2020
+ );
2021
+ });
2022
+ function getDocumentTitle(document2, defaultValue = "") {
2023
+ if (!document2) return defaultValue;
2024
+ return document2.doc_metadata?.title || document2.file_name || defaultValue;
2025
+ }
2026
+ var MAX_LABEL_CHARS = 30;
2027
+ function clampLabel(text) {
2028
+ return text.length > MAX_LABEL_CHARS ? `${text.slice(0, MAX_LABEL_CHARS).trimEnd()}\u2026` : text;
2029
+ }
2030
+ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "webp"]);
2031
+ var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set(["mp4", "mpeg", "mpg", "webm", "mov", "avi", "mkv"]);
2032
+ var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["mp3", "wav", "m4a", "aac", "ogg", "flac"]);
2033
+ var EMAIL_EXTENSIONS = /* @__PURE__ */ new Set(["eml", "msg"]);
2034
+ function getDocIcon(fileName, iconSize = 14) {
2035
+ const ext = fileName?.split(".").pop()?.toLowerCase();
2036
+ if (ext && VIDEO_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(VidIcon, { size: iconSize, className: "flex-shrink-0" });
2037
+ if (ext && AUDIO_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(AudIcon, { size: iconSize, className: "flex-shrink-0" });
2038
+ if (ext && IMAGE_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(ImgIcon, { size: iconSize, className: "flex-shrink-0" });
2039
+ if (ext && EMAIL_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(EmlIcon, { size: iconSize, className: "flex-shrink-0" });
2040
+ return /* @__PURE__ */ jsxRuntime.jsx(PdfIcon, { size: iconSize, className: "flex-shrink-0" });
2041
+ }
2042
+ function DocumentEntity({
2043
+ doc,
2044
+ icon,
2045
+ size = "sm",
2046
+ labelMaxWidth,
2047
+ onClick,
2048
+ onIconClick,
2049
+ showHoverEye,
2050
+ viewing,
2051
+ iconBadge,
2052
+ actions,
2053
+ tooltipContent,
2054
+ className,
2055
+ fullWidth
2056
+ }) {
2057
+ const title = getDocumentTitle(doc);
2058
+ const ext = doc.file_name?.split(".").pop()?.toLowerCase();
2059
+ const iconSize = size === "base" ? 16 : 14;
2060
+ const eyeSizeClass = size === "base" ? "h-4 w-4" : "h-3.5 w-3.5";
2061
+ const baseIcon = icon ?? getDocIcon(doc.file_name, iconSize);
2062
+ const showEye = showHoverEye || viewing;
2063
+ const displayIcon = showEye || iconBadge ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex flex-shrink-0 items-center justify-center", children: [
2064
+ showEye ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2065
+ /* @__PURE__ */ jsxRuntime.jsx(
2066
+ "span",
2067
+ {
2068
+ className: cn(
2069
+ "transition-opacity",
2070
+ viewing ? "opacity-0" : "group-hover/pill:opacity-0 group-has-[[data-state=open]]/pill:opacity-0"
2071
+ ),
2072
+ children: baseIcon
2073
+ }
2074
+ ),
2075
+ /* @__PURE__ */ jsxRuntime.jsx(
2076
+ lucideReact.Eye,
2077
+ {
2078
+ className: cn(
2079
+ "absolute inset-0 m-auto transition-opacity",
2080
+ eyeSizeClass,
2081
+ viewing ? "text-primary-foreground opacity-100" : "text-primary opacity-0 group-hover/pill:opacity-100 group-has-[[data-state=open]]/pill:opacity-100"
2082
+ )
2083
+ }
2084
+ )
2085
+ ] }) : baseIcon,
2086
+ iconBadge
2087
+ ] }) : baseIcon;
2088
+ const defaultTooltip = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 text-xs max-w-[300px]", children: [
2089
+ doc.folder && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 text-muted-foreground", children: [
2090
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: "h-3 w-3 text-yellow-600 shrink-0" }),
2091
+ doc.folder.split("/").map((part, i, arr) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 shrink-0", children: [
2092
+ i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 mx-0.5", children: "/" }),
2093
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: i < arr.length - 1 ? "text-muted-foreground/70" : "", children: part })
2094
+ ] }, i))
2095
+ ] }),
2096
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium break-words", children: [
2097
+ title,
2098
+ ext ? `.${ext}` : ""
2099
+ ] })
2100
+ ] });
2101
+ return /* @__PURE__ */ jsxRuntime.jsx(
2102
+ EntityPill,
2103
+ {
2104
+ icon: displayIcon,
2105
+ size,
2106
+ label: fullWidth ? title : clampLabel(title),
2107
+ labelMaxWidth: labelMaxWidth ?? "max-w-[140px]",
2108
+ fullWidth,
2109
+ onClick,
2110
+ onIconClick,
2111
+ moreContent: actions,
2112
+ className,
2113
+ highlight: viewing,
2114
+ tooltipContent: tooltipContent ?? defaultTooltip
2115
+ }
2116
+ );
2117
+ }
2118
+ var BASE_COLORS = {
2119
+ "0": "#10b981",
2120
+ "1": "#3b82f6",
2121
+ "2": "#8b5cf6",
2122
+ "3": "#f43f5e",
2123
+ "4": "#f59e0b",
2124
+ "5": "#84cc16",
2125
+ "6": "#a855f7",
2126
+ "7": "#06b6d4",
2127
+ "8": "#f97316",
2128
+ "9": "#14b8a6",
2129
+ a: "#ef4444",
2130
+ b: "#6366f1",
2131
+ c: "#ec4899",
2132
+ d: "#22c55e",
2133
+ e: "#eab308",
2134
+ f: "#0ea5e9"
2135
+ };
2136
+ function getEntityColor(entityId) {
2137
+ return BASE_COLORS[entityId[4]] || BASE_COLORS["0"];
2138
+ }
2139
+ var TAG_TYPE_LABELS = {
2140
+ checkbox: "Checkbox",
2141
+ select: "Select",
2142
+ number: "Number",
2143
+ text: "Text",
2144
+ folder: "Folder",
2145
+ search: "Saved Search",
2146
+ date: "Date",
2147
+ assistant: "AI Assistant"
2148
+ };
2149
+ var TAG_TYPE_ICONS = {
2150
+ checkbox: lucideReact.SquareCheckBig,
2151
+ select: lucideReact.List,
2152
+ number: lucideReact.Hash,
2153
+ text: lucideReact.StickyNote,
2154
+ folder: lucideReact.Folder,
2155
+ search: lucideReact.Search,
2156
+ date: lucideReact.Calendar,
2157
+ assistant: lucideReact.Bot
2158
+ };
2159
+ function TagEntity({
2160
+ tag,
2161
+ size = "md",
2162
+ className = "",
2163
+ onClick,
2164
+ showTooltip = true
2165
+ }) {
2166
+ const tagType = tag.tag_type?.type ?? "text";
2167
+ const iconSize = size === "sm" ? 12 : size === "md" ? 14 : 16;
2168
+ const Icon = TAG_TYPE_ICONS[tagType] || lucideReact.StickyNote;
2169
+ const sizeClasses = {
2170
+ sm: "p-0.5",
2171
+ md: "p-1",
2172
+ lg: "p-1.5"
2173
+ };
2174
+ const tagColor = tag.color ?? getEntityColor(tag.external_id);
2175
+ const iconElement = /* @__PURE__ */ jsxRuntime.jsx(
2176
+ "span",
2177
+ {
2178
+ className: `inline-flex items-center justify-center rounded-md text-white flex-shrink-0 ${sizeClasses[size]}`,
2179
+ style: { backgroundColor: tagColor },
2180
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: iconSize, className: "flex-shrink-0" })
2181
+ }
2182
+ );
2183
+ const pillSize = size === "lg" ? "base" : "sm";
2184
+ const tooltipContent = showTooltip ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
2185
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2186
+ /* @__PURE__ */ jsxRuntime.jsx(
2187
+ "span",
2188
+ {
2189
+ className: "inline-flex items-center justify-center rounded-md text-white p-1",
2190
+ style: { backgroundColor: tagColor },
2191
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 16 })
2192
+ }
2193
+ ),
2194
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-sm", children: tag.name })
2195
+ ] }),
2196
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5 text-sm", children: [
2197
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2198
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Type:" }),
2199
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: TAG_TYPE_LABELS[tagType] || tagType })
2200
+ ] }),
2201
+ tag.doctag_count != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2202
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Documents:" }),
2203
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", className: "h-5 min-w-[20px] justify-center", children: tag.doctag_count ?? 0 })
2204
+ ] }),
2205
+ tag.shared != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: tag.shared ? "Shared" : "Private" }) })
2206
+ ] })
2207
+ ] }) : void 0;
2208
+ return /* @__PURE__ */ jsxRuntime.jsx(
2209
+ EntityPill,
2210
+ {
2211
+ icon: iconElement,
2212
+ label: tag.name,
2213
+ size: pillSize,
2214
+ shape: "rounded",
2215
+ labelMaxWidth: "max-w-[180px]",
2216
+ tooltipContent,
2217
+ onClick,
2218
+ className,
2219
+ "data-testid": `tag-entity-${tag.external_id}`
2220
+ }
2221
+ );
2222
+ }
2223
+ var VARIANT_STYLES = {
2224
+ "mine-paid": {
2225
+ pill: "bg-primary text-primary-foreground border-transparent",
2226
+ icon: "text-primary-foreground"
2227
+ },
2228
+ other: {
2229
+ pill: "bg-secondary text-secondary-foreground border-transparent",
2230
+ icon: "text-secondary-foreground"
2231
+ },
2232
+ "mine-free": {
2233
+ pill: "bg-muted-foreground text-background border-transparent",
2234
+ icon: "text-background"
2235
+ },
2236
+ common: {
2237
+ pill: "",
2238
+ icon: "text-muted-foreground"
2239
+ }
2240
+ };
2241
+ function resolveVariant(relation, paid, hasCollaborators) {
2242
+ if (relation === "common") return "common";
2243
+ if (relation === "other") return "other";
2244
+ if (relation === "mine") return paid ? "mine-paid" : "mine-free";
2245
+ if (paid) return hasCollaborators ? "other" : "mine-paid";
2246
+ return "mine-free";
2247
+ }
2248
+ function ProjectEntity({
2249
+ name,
2250
+ label,
2251
+ icon,
2252
+ subscription = "none",
2253
+ hasCollaborators = false,
2254
+ size = "sm",
2255
+ className,
2256
+ onClick,
2257
+ relation,
2258
+ isPaid,
2259
+ tooltipContent
2260
+ }) {
2261
+ const paid = isPaid ?? (subscription === "active" || subscription === "past_due" || subscription === "dev");
2262
+ const variant = resolveVariant(relation, paid, hasCollaborators);
2263
+ const { pill, icon: iconClass } = VARIANT_STYLES[variant];
2264
+ const iconSizeClass = size === "base" ? "h-4 w-4" : "h-3.5 w-3.5";
2265
+ const iconNode = icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: cn(iconSizeClass, iconClass) });
2266
+ return /* @__PURE__ */ jsxRuntime.jsx(
2267
+ EntityPill,
2268
+ {
2269
+ icon: iconNode,
2270
+ label: label ?? name,
2271
+ size,
2272
+ shape: "pill",
2273
+ className: cn(pill, className),
2274
+ onClick,
2275
+ tooltipContent
2276
+ }
2277
+ );
2278
+ }
2279
+ var useArbiUiStore = zustand.create((set) => ({
2280
+ selectedDocIds: [],
2281
+ setSelectedDocIds: (ids) => set({ selectedDocIds: ids }),
2282
+ viewingDocId: null,
2283
+ setViewingDocId: (id) => set({ viewingDocId: id })
2284
+ }));
2285
+ agGridCommunity.ModuleRegistry.registerModules([agGridCommunity.AllCommunityModule]);
2286
+ function formatBytes(bytes) {
2287
+ if (bytes == null || Number.isNaN(bytes)) return "\u2014";
2288
+ if (bytes < 1024) return `${bytes} B`;
2289
+ const units = ["KB", "MB", "GB", "TB"];
2290
+ let value = bytes / 1024;
2291
+ let i = 0;
2292
+ while (value >= 1024 && i < units.length - 1) {
2293
+ value /= 1024;
2294
+ i++;
2295
+ }
2296
+ return `${value.toFixed(value >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
2297
+ }
2298
+ var STATUS_VARIANTS = {
2299
+ completed: "default",
2300
+ empty: "secondary",
2301
+ "low-content": "secondary",
2302
+ processing: "outline",
2303
+ queued: "outline",
2304
+ failed: "destructive",
2305
+ skipped: "destructive"
2306
+ };
2307
+ function DocumentTable({
2308
+ workspaceId,
2309
+ documents,
2310
+ onOpenDocument,
2311
+ selectedIds,
2312
+ onSelectionChange,
2313
+ height = 480,
2314
+ className
2315
+ }) {
2316
+ const query = useDocuments(workspaceId, { enabled: !documents });
2317
+ const rows = documents ?? query.data ?? [];
2318
+ const isLoading = !documents && query.isLoading;
2319
+ const tagsQuery = useTags(workspaceId);
2320
+ const tagNameById = React__namespace.default.useMemo(() => {
2321
+ const map = /* @__PURE__ */ new Map();
2322
+ for (const t of tagsQuery.data ?? []) {
2323
+ if (t.external_id) map.set(t.external_id, t.name ?? t.external_id.slice(0, 8));
2324
+ }
2325
+ return map;
2326
+ }, [tagsQuery.data]);
2327
+ const storeSelected = useArbiUiStore((s) => s.selectedDocIds);
2328
+ const storeSetSelected = useArbiUiStore((s) => s.setSelectedDocIds);
2329
+ const viewingDocId = useArbiUiStore((s) => s.viewingDocId);
2330
+ const setViewingDocId = useArbiUiStore((s) => s.setViewingDocId);
2331
+ const effectiveSelected = selectedIds ?? storeSelected;
2332
+ const emitSelection = onSelectionChange ?? storeSetSelected;
2333
+ const gridApiRef = React__namespace.default.useRef(null);
2334
+ const openDocument = React__namespace.default.useCallback(
2335
+ (id) => {
2336
+ setViewingDocId(id);
2337
+ onOpenDocument?.(id);
2338
+ },
2339
+ [onOpenDocument, setViewingDocId]
2340
+ );
2341
+ const applySelection = React__namespace.default.useCallback(() => {
2342
+ const api = gridApiRef.current;
2343
+ if (!api) return;
2344
+ const wanted = new Set(effectiveSelected);
2345
+ api.forEachNode((node) => {
2346
+ const id = node.data?.external_id;
2347
+ const shouldSelect = !!id && wanted.has(id);
2348
+ if (node.isSelected() !== shouldSelect) node.setSelected(shouldSelect);
2349
+ });
2350
+ }, [effectiveSelected]);
2351
+ React__namespace.default.useEffect(() => {
2352
+ applySelection();
2353
+ }, [applySelection]);
2354
+ const columnDefs = React__namespace.default.useMemo(
2355
+ () => [
2356
+ {
2357
+ colId: "select",
2358
+ headerName: "",
2359
+ width: 44,
2360
+ pinned: "left",
2361
+ checkboxSelection: true,
2362
+ headerCheckboxSelection: true,
2363
+ sortable: false,
2364
+ filter: false,
2365
+ resizable: false,
2366
+ suppressMovable: true
2367
+ },
2368
+ {
2369
+ colId: "title",
2370
+ headerName: "Document Name",
2371
+ flex: 3,
2372
+ minWidth: 240,
2373
+ sortable: true,
2374
+ valueGetter: (p) => p.data?.doc_metadata?.title || p.data?.file_name || "",
2375
+ cellRenderer: (p) => {
2376
+ const doc = p.data;
2377
+ if (!doc) return null;
2378
+ return /* @__PURE__ */ jsxRuntime.jsx(
2379
+ DocumentEntity,
2380
+ {
2381
+ doc,
2382
+ size: "base",
2383
+ fullWidth: true,
2384
+ showHoverEye: true,
2385
+ viewing: viewingDocId === doc.external_id,
2386
+ onClick: (e) => {
2387
+ e.stopPropagation();
2388
+ if (doc.external_id) openDocument(doc.external_id);
2389
+ }
2390
+ }
2391
+ );
2392
+ }
2393
+ },
2394
+ {
2395
+ colId: "status",
2396
+ headerName: "Status",
2397
+ width: 140,
2398
+ sortable: true,
2399
+ field: "status",
2400
+ cellRenderer: (p) => {
2401
+ const status = p.data?.status;
2402
+ if (!status) return null;
2403
+ return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: STATUS_VARIANTS[status.toLowerCase()] ?? "secondary", children: status });
2404
+ }
2405
+ },
2406
+ {
2407
+ colId: "all_tags",
2408
+ headerName: "Labels",
2409
+ flex: 1,
2410
+ minWidth: 160,
2411
+ sortable: false,
2412
+ filter: false,
2413
+ cellRenderer: (p) => {
2414
+ const doctags = p.data?.doctags ?? [];
2415
+ if (doctags.length === 0) return null;
2416
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1 py-1", children: doctags.map((dt) => /* @__PURE__ */ jsxRuntime.jsx(
2417
+ TagEntity,
2418
+ {
2419
+ size: "sm",
2420
+ tag: {
2421
+ external_id: dt.tag_ext_id,
2422
+ name: tagNameById.get(dt.tag_ext_id) ?? dt.tag_ext_id.slice(0, 8)
2423
+ }
2424
+ },
2425
+ dt.tag_ext_id
2426
+ )) });
2427
+ }
2428
+ },
2429
+ {
2430
+ colId: "file_size",
2431
+ headerName: "Size",
2432
+ width: 110,
2433
+ sortable: true,
2434
+ field: "file_size",
2435
+ valueFormatter: (p) => formatBytes(p.value)
2436
+ },
2437
+ {
2438
+ colId: "folder",
2439
+ headerName: "Folder",
2440
+ flex: 1,
2441
+ minWidth: 140,
2442
+ sortable: true,
2443
+ field: "folder",
2444
+ valueFormatter: (p) => p.value || "\u2014"
2445
+ }
2446
+ ],
2447
+ [openDocument, viewingDocId, tagNameById]
2448
+ );
2449
+ const handleGridReady = (e) => {
2450
+ gridApiRef.current = e.api;
2451
+ applySelection();
2452
+ };
2453
+ const handleSelectionChanged = (e) => {
2454
+ const ids = e.api.getSelectedRows().map((r) => r.external_id).filter((id) => !!id);
2455
+ emitSelection(ids);
2456
+ };
2457
+ const handleRowClicked = (e) => {
2458
+ const id = e.data?.external_id;
2459
+ if (id) openDocument(id);
2460
+ };
2461
+ const getRowId = React__namespace.default.useCallback((params) => params.data.external_id, []);
2462
+ const autoHeight = height === "auto";
2463
+ const style = autoHeight ? {} : { height: typeof height === "number" ? `${height}px` : height, width: "100%" };
2464
+ if (isLoading) {
2465
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center p-8 text-sm text-muted-foreground", children: "Loading documents\u2026" }) });
2466
+ }
2467
+ if (rows.length === 0) {
2468
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center p-8 text-sm text-muted-foreground", children: "No documents" }) });
2469
+ }
2470
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx(
2471
+ agGridReact.AgGridReact,
2472
+ {
2473
+ columnDefs,
2474
+ rowData: rows,
2475
+ getRowId,
2476
+ rowSelection: "multiple",
2477
+ suppressRowClickSelection: true,
2478
+ domLayout: autoHeight ? "autoHeight" : "normal",
2479
+ rowHeight: 44,
2480
+ onGridReady: handleGridReady,
2481
+ onSelectionChanged: handleSelectionChanged,
2482
+ onRowClicked: handleRowClicked
2483
+ }
2484
+ ) });
2485
+ }
1158
2486
 
1159
2487
  Object.defineProperty(exports, "Arbi", {
1160
2488
  enumerable: true,
@@ -1165,17 +2493,49 @@ Object.defineProperty(exports, "ArbiError", {
1165
2493
  get: function () { return browser.ArbiError; }
1166
2494
  });
1167
2495
  exports.ArbiChat = ArbiChat;
2496
+ exports.ArbiChatPanel = ArbiChatPanel;
1168
2497
  exports.ArbiProvider = ArbiProvider;
2498
+ exports.AudIcon = AudIcon;
2499
+ exports.Avatar = Avatar;
2500
+ exports.AvatarFallback = AvatarFallback;
2501
+ exports.AvatarImage = AvatarImage;
2502
+ exports.Badge = Badge;
2503
+ exports.Button = Button;
2504
+ exports.DocumentEntity = DocumentEntity;
2505
+ exports.DocumentTable = DocumentTable;
2506
+ exports.EmlIcon = EmlIcon;
2507
+ exports.EntityPill = EntityPill;
2508
+ exports.FILE_TYPE_COLORS = FILE_TYPE_COLORS;
2509
+ exports.FileIcon = FileIcon;
2510
+ exports.HoverCard = HoverCard;
2511
+ exports.HoverCardContent = HoverCardContent;
2512
+ exports.HoverCardTrigger = HoverCardTrigger;
2513
+ exports.ImgIcon = ImgIcon;
2514
+ exports.PdfIcon = PdfIcon;
2515
+ exports.ProjectEntity = ProjectEntity;
2516
+ exports.TagEntity = TagEntity;
2517
+ exports.Tooltip = Tooltip;
2518
+ exports.TooltipContent = TooltipContent;
2519
+ exports.TooltipProvider = TooltipProvider;
2520
+ exports.TooltipTrigger = TooltipTrigger;
2521
+ exports.VidIcon = VidIcon;
1169
2522
  exports.arbiQueryKeys = arbiQueryKeys;
2523
+ exports.badgeVariants = badgeVariants;
2524
+ exports.buttonVariants = buttonVariants;
2525
+ exports.cn = cn;
1170
2526
  exports.useAgents = useAgents;
1171
2527
  exports.useArbi = useArbi;
2528
+ exports.useArbiUiStore = useArbiUiStore;
1172
2529
  exports.useAssistantQuery = useAssistantQuery;
2530
+ exports.useConfigs = useConfigs;
1173
2531
  exports.useConversations = useConversations;
1174
2532
  exports.useDeleteAgents = useDeleteAgents;
1175
2533
  exports.useDocuments = useDocuments;
1176
2534
  exports.useHealth = useHealth;
2535
+ exports.useMemories = useMemories;
1177
2536
  exports.useSessions = useSessions;
1178
2537
  exports.useTags = useTags;
2538
+ exports.useTasks = useTasks;
1179
2539
  exports.useWorkspaces = useWorkspaces;
1180
2540
  //# sourceMappingURL=index.cjs.map
1181
2541
  //# sourceMappingURL=index.cjs.map