@arbidocs/blocks 0.5.48 → 0.5.50

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.
Files changed (81) hide show
  1. package/dist/DocumentReviewCard-DLR4XOIZ.cjs +516 -0
  2. package/dist/DocumentReviewCard-DLR4XOIZ.cjs.map +1 -0
  3. package/dist/DocumentReviewCard-Y67FFRPC.js +514 -0
  4. package/dist/DocumentReviewCard-Y67FFRPC.js.map +1 -0
  5. package/dist/calls/connected/ConnectedCallPage.d.ts +23 -0
  6. package/dist/calls/connected/index.d.ts +1 -0
  7. package/dist/calls/index.cjs +172 -0
  8. package/dist/calls/index.cjs.map +1 -1
  9. package/dist/calls/index.js +175 -4
  10. package/dist/calls/index.js.map +1 -1
  11. package/dist/chunk-3Y4UTPCD.js +1521 -0
  12. package/dist/chunk-3Y4UTPCD.js.map +1 -0
  13. package/dist/chunk-5TDGVOR5.js +142 -0
  14. package/dist/chunk-5TDGVOR5.js.map +1 -0
  15. package/dist/{chunk-QKOFQMAY.cjs → chunk-5YX3R6CK.cjs} +5 -4
  16. package/dist/chunk-5YX3R6CK.cjs.map +1 -0
  17. package/dist/chunk-63IH7V5F.js +13 -0
  18. package/dist/chunk-63IH7V5F.js.map +1 -0
  19. package/dist/chunk-C3VTWM74.js +123 -0
  20. package/dist/chunk-C3VTWM74.js.map +1 -0
  21. package/dist/chunk-DVE6NNZ2.cjs +15 -0
  22. package/dist/chunk-DVE6NNZ2.cjs.map +1 -0
  23. package/dist/{chunk-XBITXJZU.js → chunk-EQ433QPZ.js} +4 -3
  24. package/dist/chunk-EQ433QPZ.js.map +1 -0
  25. package/dist/{chunk-UAEYU2NN.cjs → chunk-H32DV7XS.cjs} +2 -136
  26. package/dist/chunk-H32DV7XS.cjs.map +1 -0
  27. package/dist/{chunk-EARQ2CUX.js → chunk-IQ3VDTR7.js} +6 -119
  28. package/dist/chunk-IQ3VDTR7.js.map +1 -0
  29. package/dist/chunk-NUQ3RY7M.cjs +130 -0
  30. package/dist/chunk-NUQ3RY7M.cjs.map +1 -0
  31. package/dist/{chunk-V2UQR7P6.cjs → chunk-QLY22ZZW.cjs} +9 -8
  32. package/dist/chunk-QLY22ZZW.cjs.map +1 -0
  33. package/dist/chunk-REH7PX3N.cjs +145 -0
  34. package/dist/chunk-REH7PX3N.cjs.map +1 -0
  35. package/dist/{chunk-VQHXVY26.cjs → chunk-RTS3B2W7.cjs} +2 -121
  36. package/dist/chunk-RTS3B2W7.cjs.map +1 -0
  37. package/dist/chunk-S7B5E3RU.cjs +1553 -0
  38. package/dist/chunk-S7B5E3RU.cjs.map +1 -0
  39. package/dist/{chunk-WZ63HE2C.js → chunk-XRL4R2TT.js} +4 -136
  40. package/dist/chunk-XRL4R2TT.js.map +1 -0
  41. package/dist/{chunk-E6EYRQC2.js → chunk-YYZH6VRP.js} +6 -5
  42. package/dist/chunk-YYZH6VRP.js.map +1 -0
  43. package/dist/connect/index.cjs +464 -1861
  44. package/dist/connect/index.cjs.map +1 -1
  45. package/dist/connect/index.js +55 -1538
  46. package/dist/connect/index.js.map +1 -1
  47. package/dist/connect/viewer.cjs +39 -39
  48. package/dist/connect/viewer.js +1 -1
  49. package/dist/connection/config/useDeveloperConfig.d.ts +1 -1
  50. package/dist/connection/files/fields/DocumentFieldParts.d.ts +2 -1
  51. package/dist/connection/files/fields/documentField.d.ts +1 -0
  52. package/dist/connection/files/grid/cells.d.ts +1 -0
  53. package/dist/connection/files/page/ConnectedFilesPage.d.ts +5 -2
  54. package/dist/connection/files/review/DocumentReviewCard.d.ts +32 -0
  55. package/dist/connection/files/review/useDocumentValueWrites.d.ts +15 -0
  56. package/dist/connection/files/review/useReviewColumns.d.ts +33 -0
  57. package/dist/files/cells/RelatedDocsCell.d.ts +3 -1
  58. package/dist/files/index.cjs +221 -221
  59. package/dist/files/index.js +1 -1
  60. package/dist/home/index.cjs +7 -6
  61. package/dist/home/index.cjs.map +1 -1
  62. package/dist/home/index.js +2 -1
  63. package/dist/home/index.js.map +1 -1
  64. package/dist/index.cjs +82 -82
  65. package/dist/index.cjs.map +1 -1
  66. package/dist/index.js +5 -8
  67. package/dist/index.js.map +1 -1
  68. package/dist/workspaces/index.cjs +29 -28
  69. package/dist/workspaces/index.cjs.map +1 -1
  70. package/dist/workspaces/index.js +4 -3
  71. package/dist/workspaces/index.js.map +1 -1
  72. package/node_modules/@arbidocs/coedit/package.json +1 -1
  73. package/package.json +5 -5
  74. package/dist/chunk-E6EYRQC2.js.map +0 -1
  75. package/dist/chunk-EARQ2CUX.js.map +0 -1
  76. package/dist/chunk-QKOFQMAY.cjs.map +0 -1
  77. package/dist/chunk-UAEYU2NN.cjs.map +0 -1
  78. package/dist/chunk-V2UQR7P6.cjs.map +0 -1
  79. package/dist/chunk-VQHXVY26.cjs.map +0 -1
  80. package/dist/chunk-WZ63HE2C.js.map +0 -1
  81. package/dist/chunk-XBITXJZU.js.map +0 -1
@@ -0,0 +1,1521 @@
1
+ "use client";
2
+ import { ExplorerFileTile, formatFolderSegment, hasFolderProviderIcon, FolderProviderIcon, ExplorerFolderTile, StatusPill, FailedStageIcon, DocumentNameCellFrame, DocumentRowMenu, visibilityToggleTooltip, FolderCell, FolderCommandList, RelatedDocsCell, DOCUMENTS_ROW_HEIGHT_INITIAL, ExplorerFileTooltip, visibilityAudience, FieldValue, FieldFolderSelect, FieldFolderValue, FieldNativeSelect, FieldWithAttribution, FieldLabelsSelect, FieldAttribution } from './chunk-YYZH6VRP.js';
3
+ import { SharedCell, EntityTooltip, EntityTooltipHeader } from './chunk-C3VTWM74.js';
4
+ import { LabelMultiSelectView } from './chunk-JMQLTMJ7.js';
5
+ import { GridView } from './chunk-7F5Z4K5W.js';
6
+ import { useBlocksEnvironment } from './chunk-KOOC6VD3.js';
7
+ import { ModalSection } from './chunk-TX2ZICS7.js';
8
+ import { getFileTypeIcon, DocumentEntity, cn, getDocumentTitle, UserEntity, getUserAvatarColor, isAgent, agentAvatarColors, getUserDisplayName, getUserInitials, formatFolderLabel, getEntityLabel, getEntityColor, VisibilityIcon, formatFriendlyDate, getDocumentSubject, Avatar, AvatarImage, AvatarFallback, formatRelativeTime, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Button, getTagTypeIcon, getTagTypeLabel, Badge, VisibilityToggle, TagEntity, DebouncedInput, Textarea, formatDocDate, getDocumentDate, friendlyFileType } from '@arbidocs/react/ui';
9
+ import { memo, useMemo, useRef, useEffect, useCallback, useState } from 'react';
10
+ import { SquarePen, BookOpen, MessagesSquare, Pencil, Download, Mail, FolderInput, Trash2, Eye, Sparkles, Play, ArrowDownToLine, RefreshCw, Zap, AlertTriangle, FileX, SkipForward, Loader2, Clock, CheckCircle, WifiOff, CircleCheck, RotateCcw } from 'lucide-react';
11
+ import { SIGNED_LOCKED_REASON, isSignedVersion, currentHasMarkup, fetchMarkupPdf, downloadBlob, useIsOnline } from '@arbidocs/react/document-tools';
12
+ import { IN_FLIGHT_DOCUMENT_STATUSES, useOfflineDocumentIds, useOpenViewerDocumentId, FINISHED_DOCUMENT_STATUSES, useMailPolicy, useProcessingTasks, resolveDocumentStatus, useArbi, useIsCreatingTag, useProcessingTask, useDocumentPendingSync, useTags, usePendingSyncItems, useCancelManyPendingSync, useDocumentsSupport, useDocumentHostActions, useWorkspaceUsers } from '@arbidocs/react';
13
+ import { create } from 'zustand';
14
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
+ import { useDraggable, useDroppable } from '@dnd-kit/core';
16
+ import { persist, createJSONStorage } from 'zustand/middleware';
17
+ import { isLabelTag, isAnnotationTag } from '@arbidocs/sdk/browser';
18
+
19
+ var usePendingSyncDialog = create((set) => ({
20
+ open: false,
21
+ setOpen: (open) => set({ open })
22
+ }));
23
+ function openPendingSyncDialog() {
24
+ usePendingSyncDialog.getState().setOpen(true);
25
+ }
26
+ var STATUS_META = {
27
+ queued: { dot: "bg-yellow-text", text: "Waiting to sync", tone: "text-yellow-text" },
28
+ syncing: { dot: "bg-blue-text", text: "Syncing\u2026", tone: "text-blue-text" },
29
+ error: { dot: "bg-red-text", text: "Failed", tone: "text-red-text" }
30
+ };
31
+ function StatusCell({ data }) {
32
+ if (!data) return null;
33
+ const meta = STATUS_META[data.status];
34
+ return /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1.5 text-sm font-medium ${meta.tone}`, children: [
35
+ /* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 rounded-full ${meta.dot}` }),
36
+ meta.text
37
+ ] });
38
+ }
39
+ function ConnectedPendingSyncDialog() {
40
+ const isOpen = usePendingSyncDialog((s) => s.open);
41
+ const setOpen = usePendingSyncDialog((s) => s.setOpen);
42
+ const isOnline = useIsOnline();
43
+ const items = usePendingSyncItems();
44
+ const cancelMany = useCancelManyPendingSync();
45
+ const [selected, setSelected] = useState([]);
46
+ const undoableIds = useMemo(
47
+ () => items.filter((i) => i.status !== "syncing").map((i) => i.mutationId),
48
+ [items]
49
+ );
50
+ const selectedUndoableIds = useMemo(
51
+ () => selected.filter((i) => i.status !== "syncing").map((i) => i.mutationId),
52
+ [selected]
53
+ );
54
+ const columnDefs = useMemo(
55
+ () => [
56
+ {
57
+ colId: "document",
58
+ headerName: "Document",
59
+ field: "document",
60
+ flex: 1,
61
+ minWidth: 140,
62
+ tooltipField: "document"
63
+ },
64
+ {
65
+ colId: "change",
66
+ headerName: "Change",
67
+ field: "change",
68
+ flex: 1.4,
69
+ minWidth: 160,
70
+ tooltipField: "change"
71
+ },
72
+ {
73
+ colId: "when",
74
+ headerName: "When",
75
+ width: 120,
76
+ // Sort by the raw timestamp; display the friendly relative string.
77
+ valueGetter: (p) => p.data?.at ?? 0,
78
+ valueFormatter: (p) => p.value ? formatRelativeTime(new Date(Number(p.value)).toISOString(), { style: "short" }) : ""
79
+ },
80
+ {
81
+ colId: "status",
82
+ headerName: "Status",
83
+ width: 150,
84
+ valueGetter: (p) => p.data?.status ?? "",
85
+ cellRenderer: StatusCell
86
+ }
87
+ ],
88
+ []
89
+ );
90
+ const hasFailed = items.some((i) => i.status === "error");
91
+ const title = !isOnline ? "Offline changes" : hasFailed ? "Some changes didn\u2019t sync" : items.length > 0 ? "Syncing your changes" : "No changes waiting";
92
+ const description = !isOnline ? "These edits are saved on this device and will sync automatically when you reconnect." : hasFailed ? "These edits didn\u2019t reach the server, so they\u2019re only saved on this device. Undo to discard them." : "Edits you made offline are syncing to the server.";
93
+ const undoSelected = () => {
94
+ cancelMany(selectedUndoableIds);
95
+ setSelected([]);
96
+ };
97
+ const undoAll = () => {
98
+ cancelMany(undoableIds);
99
+ setSelected([]);
100
+ };
101
+ return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(DialogContent, { presentation: "sheet", className: "sm:max-w-2xl", "data-testid": "pending-sync-modal", children: [
102
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
103
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
104
+ isOnline ? /* @__PURE__ */ jsx(RefreshCw, { className: "h-5 w-5 text-primary" }) : /* @__PURE__ */ jsx(WifiOff, { className: "h-5 w-5 text-yellow-text" }),
105
+ title
106
+ ] }),
107
+ /* @__PURE__ */ jsx(DialogDescription, { children: description })
108
+ ] }),
109
+ items.length === 0 ? /* @__PURE__ */ jsxs(ModalSection, { className: "flex flex-col items-center gap-2 py-10 text-center text-muted-foreground", children: [
110
+ /* @__PURE__ */ jsx(CircleCheck, { className: "h-6 w-6 text-green-text opacity-70" }),
111
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "Everything is up to date." })
112
+ ] }) : /* @__PURE__ */ jsx(ModalSection, { children: /* @__PURE__ */ jsx(
113
+ GridView,
114
+ {
115
+ items,
116
+ columnDefs,
117
+ getItemId: (item) => String(item.mutationId),
118
+ selection: { mode: "multiple", selected, onSelectionChange: setSelected },
119
+ height: "320px",
120
+ gridId: "pending-sync-grid-v1"
121
+ }
122
+ ) }),
123
+ undoableIds.length > 0 && /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsxs(
124
+ Button,
125
+ {
126
+ variant: "outline",
127
+ className: "gap-1.5",
128
+ "data-testid": "pending-sync-undo",
129
+ disabled: selected.length > 0 && selectedUndoableIds.length === 0,
130
+ onClick: selected.length > 0 ? undoSelected : undoAll,
131
+ children: [
132
+ /* @__PURE__ */ jsx(RotateCcw, { className: "h-4 w-4" }),
133
+ selected.length > 0 ? `Undo selected (${selectedUndoableIds.length})` : `Undo all (${undoableIds.length})`
134
+ ]
135
+ }
136
+ ) })
137
+ ] }) });
138
+ }
139
+ function DocumentSyncGlyph({
140
+ docExtId,
141
+ size = 13,
142
+ className,
143
+ bgClassName = "bg-muted-foreground"
144
+ }) {
145
+ const isAvailableOffline = useOfflineDocumentIds().has(docExtId);
146
+ if (!isAvailableOffline) return null;
147
+ return /* @__PURE__ */ jsx(
148
+ "span",
149
+ {
150
+ title: "Available offline (saved on this device)",
151
+ "aria-label": "Available offline",
152
+ "data-testid": `offline-available-badge-${docExtId}`,
153
+ className: cn(
154
+ "inline-flex items-center justify-center rounded-full text-white ring-1 ring-white",
155
+ bgClassName,
156
+ className
157
+ ),
158
+ style: { width: size, height: size },
159
+ children: /* @__PURE__ */ jsx(ArrowDownToLine, { size: Math.round(size * 0.7), strokeWidth: 2.75 })
160
+ }
161
+ );
162
+ }
163
+ var NO_ACTIONS = {};
164
+ var ACTIVE_STATUSES = IN_FLIGHT_DOCUMENT_STATUSES;
165
+ var TERMINAL_STATUSES = FINISHED_DOCUMENT_STATUSES;
166
+ var STATUS_LABEL = {
167
+ uploading: "Uploading",
168
+ queued: "Queued",
169
+ parsing: "Parsing",
170
+ encrypting: "Encrypting",
171
+ indexing: "Indexing",
172
+ analysing: "Analysing"
173
+ };
174
+ function isActiveDocumentStatus(status) {
175
+ return ACTIVE_STATUSES.has(status.toLowerCase());
176
+ }
177
+ function useDocStatus(doc) {
178
+ return resolveDocumentStatus(doc, useProcessingTask(doc.external_id));
179
+ }
180
+ function TileStatusBadge({ doc, status }) {
181
+ let tone = "neutral";
182
+ let icon = null;
183
+ let title = "";
184
+ switch (status) {
185
+ case "completed":
186
+ tone = "success";
187
+ icon = /* @__PURE__ */ jsx(CheckCircle, { className: "size-4 text-green-text", strokeWidth: 2.75 });
188
+ title = "Ready";
189
+ break;
190
+ case "failed":
191
+ tone = "danger";
192
+ icon = /* @__PURE__ */ jsx(
193
+ FailedStageIcon,
194
+ {
195
+ stage: doc.failed_stage ?? null,
196
+ errorMessage: doc.error_message,
197
+ className: "size-4 text-red-text"
198
+ }
199
+ );
200
+ title = "Failed";
201
+ break;
202
+ case "skipped":
203
+ icon = /* @__PURE__ */ jsx(SkipForward, { className: "size-4 text-muted-foreground", strokeWidth: 2.75 });
204
+ title = "Skipped";
205
+ break;
206
+ case "empty":
207
+ tone = "warning";
208
+ icon = /* @__PURE__ */ jsx(FileX, { className: "size-4 text-yellow-text", strokeWidth: 2.75 });
209
+ title = "Empty \u2014 no extractable content";
210
+ break;
211
+ case "low-content":
212
+ tone = "warning";
213
+ icon = /* @__PURE__ */ jsx(AlertTriangle, { className: "size-4 text-yellow-text", strokeWidth: 2.75 });
214
+ title = "Low content \u2014 minimal extractable content";
215
+ break;
216
+ default:
217
+ return null;
218
+ }
219
+ return /* @__PURE__ */ jsx(
220
+ StatusPill,
221
+ {
222
+ tone,
223
+ icon,
224
+ title,
225
+ testId: `explorer-file-status-${doc.external_id}`
226
+ }
227
+ );
228
+ }
229
+ function TileVisibilityBadge({ doc }) {
230
+ const shared = !!doc.shared;
231
+ return /* @__PURE__ */ jsx(
232
+ StatusPill,
233
+ {
234
+ icon: /* @__PURE__ */ jsx(VisibilityIcon, { isShared: shared, className: "size-3.5", "aria-hidden": true }),
235
+ label: shared ? getEntityLabel("WORKSPACE") : "Only you",
236
+ title: visibilityAudience(shared),
237
+ testId: `explorer-file-visibility-${doc.external_id}`
238
+ }
239
+ );
240
+ }
241
+ function MiniUserAvatar({ user }) {
242
+ return /* @__PURE__ */ jsxs(Avatar, { className: "h-4 w-4 border border-white", children: [
243
+ user.picture && /* @__PURE__ */ jsx(AvatarImage, { src: user.picture, alt: getUserDisplayName(user) }),
244
+ /* @__PURE__ */ jsx(
245
+ AvatarFallback,
246
+ {
247
+ className: cn(
248
+ "text-xs font-semibold leading-none text-white",
249
+ getUserAvatarColor(user.external_id)
250
+ ),
251
+ children: getUserInitials(user)
252
+ }
253
+ )
254
+ ] });
255
+ }
256
+ function FileTooltipContent({
257
+ doc,
258
+ modifiedBy,
259
+ tagNameById
260
+ }) {
261
+ const labels = (doc.doctags ?? []).map((dt) => tagNameById.get(dt.tag_ext_id)).filter((name) => !!name);
262
+ return /* @__PURE__ */ jsx(
263
+ ExplorerFileTooltip,
264
+ {
265
+ title: getDocumentTitle(doc, doc.file_name ?? ""),
266
+ summary: getDocumentSubject(doc),
267
+ modifiedLabel: doc.updated_at ? formatFriendlyDate(doc.updated_at, false) : null,
268
+ modifiedByAvatar: modifiedBy && /* @__PURE__ */ jsx(MiniUserAvatar, { user: modifiedBy }),
269
+ shared: !!doc.shared,
270
+ visibilityIcon: /* @__PURE__ */ jsx(VisibilityIcon, { isShared: !!doc.shared, className: "h-3 w-3" }),
271
+ labels,
272
+ uiLabels: { shared: visibilityAudience(true), private: visibilityAudience(false) }
273
+ }
274
+ );
275
+ }
276
+ function startMenuItem(items) {
277
+ if (items.length === 0) return [];
278
+ return [
279
+ {
280
+ id: "start",
281
+ label: "Start\u2026",
282
+ icon: Sparkles,
283
+ testId: "explorer-start-menu",
284
+ onSelect: () => {
285
+ },
286
+ submenu: items.map((item) => ({
287
+ id: item.id,
288
+ label: item.title,
289
+ icon: Play,
290
+ onSelect: item.run,
291
+ testId: `explorer-start-${item.id}`
292
+ }))
293
+ }
294
+ ];
295
+ }
296
+ var FileTile = memo(function FileTile2({
297
+ doc,
298
+ density,
299
+ selected,
300
+ dragging,
301
+ dndActive,
302
+ renaming,
303
+ canDelete,
304
+ thumbnailUrl,
305
+ modifiedBy,
306
+ tagNameById,
307
+ onSelect,
308
+ onToggle,
309
+ onOpen,
310
+ onReview,
311
+ onStartRename,
312
+ onCommitRename,
313
+ onCancelRename,
314
+ onDownload,
315
+ onMove,
316
+ onDelete,
317
+ actions = NO_ACTIONS
318
+ }) {
319
+ const { attributes, listeners, setNodeRef } = useDraggable({
320
+ id: `doc:${doc.external_id}`,
321
+ data: { type: "doc", docId: doc.external_id }
322
+ });
323
+ const { notify } = useBlocksEnvironment();
324
+ const { startItemsForFile, openDocumentChat, emailDocument } = actions;
325
+ const status = useDocStatus(doc);
326
+ const isProcessing = ACTIVE_STATUSES.has(status);
327
+ const isOffline = useOfflineDocumentIds().has(doc.external_id);
328
+ const isViewing = useOpenViewerDocumentId() === doc.external_id;
329
+ const showStatusMarker = !isProcessing && TERMINAL_STATUSES.has(status);
330
+ const Icon = getFileTypeIcon(doc.file_name, { mime: doc.file_type });
331
+ const { data: mailPolicy } = useMailPolicy();
332
+ const shareAsEmail = async () => {
333
+ try {
334
+ await emailDocument?.(doc);
335
+ } catch (error) {
336
+ notify(error instanceof Error ? error.message : "Could not attach document", "error");
337
+ }
338
+ };
339
+ const startItems = startItemsForFile?.(doc);
340
+ const menuItems = [
341
+ { id: "open", label: "Open", icon: SquarePen, onSelect: () => onOpen(doc) },
342
+ ...onReview ? [{ id: "review", label: "Open in Review", icon: BookOpen, onSelect: () => onReview(doc) }] : [],
343
+ ...openDocumentChat ? [
344
+ {
345
+ id: "chat",
346
+ label: "Document chat",
347
+ icon: MessagesSquare,
348
+ onSelect: () => openDocumentChat(doc.external_id)
349
+ }
350
+ ] : [],
351
+ ...startMenuItem(startItems ?? []),
352
+ {
353
+ id: "rename",
354
+ label: "Rename",
355
+ icon: Pencil,
356
+ onSelect: () => onStartRename(doc),
357
+ separatorBefore: true
358
+ },
359
+ { id: "download", label: "Download", icon: Download, onSelect: () => onDownload(doc) },
360
+ ...emailDocument && mailPolicy?.enabled ? [
361
+ {
362
+ id: "email",
363
+ label: "Send as email attachment",
364
+ icon: Mail,
365
+ onSelect: () => {
366
+ void shareAsEmail();
367
+ }
368
+ }
369
+ ] : [],
370
+ ...onMove ? [{ id: "move", label: "Move to\u2026", icon: FolderInput, onSelect: () => onMove(doc) }] : [],
371
+ ...canDelete ? [
372
+ {
373
+ id: "delete",
374
+ label: "Delete",
375
+ icon: Trash2,
376
+ onSelect: () => onDelete(doc),
377
+ destructive: true,
378
+ separatorBefore: true
379
+ }
380
+ ] : []
381
+ ];
382
+ const tooltip = renaming || dndActive ? void 0 : /* @__PURE__ */ jsx(FileTooltipContent, { doc, modifiedBy, tagNameById });
383
+ return /* @__PURE__ */ jsx(
384
+ ExplorerFileTile,
385
+ {
386
+ id: doc.external_id,
387
+ title: getDocumentTitle(doc, doc.file_name ?? ""),
388
+ density,
389
+ selected,
390
+ dragging,
391
+ renaming,
392
+ thumbnailUrl,
393
+ renderFileIcon: (size) => /* @__PURE__ */ jsx(Icon, { size, className: "drop-shadow-sm" }),
394
+ progress: isProcessing ? { label: STATUS_LABEL[status] ?? status, queued: status === "queued" } : void 0,
395
+ statusMarker: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
396
+ /* @__PURE__ */ jsx(TileVisibilityBadge, { doc }),
397
+ showStatusMarker && /* @__PURE__ */ jsx(TileStatusBadge, { doc, status })
398
+ ] }),
399
+ offlineMarker: isOffline ? /* @__PURE__ */ jsx(DocumentSyncGlyph, { docExtId: doc.external_id, size: 24, bgClassName: "bg-primary" }) : void 0,
400
+ entity: /* @__PURE__ */ jsx(
401
+ DocumentEntity,
402
+ {
403
+ doc,
404
+ labelMaxWidth: "max-w-full",
405
+ noClamp: true,
406
+ labelClassName: "whitespace-normal line-clamp-2 break-words",
407
+ viewing: isViewing,
408
+ tooltipContent: /* @__PURE__ */ jsx(FileTooltipContent, { doc, modifiedBy, tagNameById }),
409
+ className: cn(
410
+ "w-full min-w-0 max-w-full bg-background/90 backdrop-blur-sm",
411
+ density === "list" ? "text-xs" : void 0
412
+ ),
413
+ onClick: (e) => {
414
+ e.stopPropagation();
415
+ onOpen(doc);
416
+ }
417
+ }
418
+ ),
419
+ tooltip,
420
+ menuItems,
421
+ rootRef: setNodeRef,
422
+ rootProps: { ...listeners, ...attributes },
423
+ onOpen: () => onOpen(doc),
424
+ onSelect: (e) => onSelect(doc, e),
425
+ onToggle: (e) => onToggle(doc, e),
426
+ onCommitRename: (name) => onCommitRename(doc, name),
427
+ onCancelRename
428
+ }
429
+ );
430
+ });
431
+ var FolderTile = memo(function FolderTile2({
432
+ folder,
433
+ density,
434
+ editing,
435
+ selected,
436
+ partiallySelected,
437
+ documents,
438
+ onOpen,
439
+ onToggleSelect,
440
+ onCommitName,
441
+ onCancelName,
442
+ onStartRename,
443
+ onDownload,
444
+ onMove,
445
+ onDelete,
446
+ actions = NO_ACTIONS
447
+ }) {
448
+ const { setNodeRef, isOver } = useDroppable({
449
+ id: `folder:${folder.path.join("/")}`,
450
+ data: { type: "folder", path: folder.path }
451
+ });
452
+ const { startItemsForFolder } = actions;
453
+ const tasks = useProcessingTasks();
454
+ const processingCount = useMemo(
455
+ () => documents.filter(
456
+ (doc) => isActiveDocumentStatus(resolveDocumentStatus(doc, tasks[doc.external_id]))
457
+ ).length,
458
+ [documents, tasks]
459
+ );
460
+ const isEmpty = folder.count === 0;
461
+ const iconSize = density === "list" ? 34 : 48;
462
+ const menuItems = [
463
+ ...onStartRename ? [{ id: "rename", label: "Rename", icon: Pencil, onSelect: () => onStartRename(folder) }] : [],
464
+ ...!isEmpty ? startMenuItem(startItemsForFolder?.(folder.path.join("/")) ?? []) : [],
465
+ ...onDownload && !isEmpty ? [{ id: "download", label: "Download", icon: Download, onSelect: () => onDownload(folder) }] : [],
466
+ ...onMove && !isEmpty ? [{ id: "move", label: "Move to\u2026", icon: FolderInput, onSelect: () => onMove(folder) }] : [],
467
+ ...onDelete ? [
468
+ {
469
+ id: "delete",
470
+ label: "Delete",
471
+ icon: Trash2,
472
+ onSelect: () => onDelete(folder),
473
+ destructive: true,
474
+ separatorBefore: true
475
+ }
476
+ ] : []
477
+ ];
478
+ const displayName = folder.path.length === 1 ? formatFolderSegment(folder.name) : folder.name;
479
+ const providerIcon = folder.path.length === 1 && hasFolderProviderIcon(folder.name) ? /* @__PURE__ */ jsx(
480
+ "span",
481
+ {
482
+ className: "flex items-center justify-center drop-shadow-sm",
483
+ style: { width: iconSize, height: iconSize },
484
+ children: /* @__PURE__ */ jsx(FolderProviderIcon, { folderPath: folder.name, className: "h-full w-full" })
485
+ }
486
+ ) : void 0;
487
+ return /* @__PURE__ */ jsx(
488
+ ExplorerFolderTile,
489
+ {
490
+ name: folder.name,
491
+ displayName: displayName === "" ? null : displayName,
492
+ path: folder.path,
493
+ count: folder.count,
494
+ density,
495
+ editing,
496
+ selected,
497
+ partiallySelected,
498
+ processingCount,
499
+ isOver,
500
+ icon: providerIcon,
501
+ menuItems,
502
+ rootRef: setNodeRef,
503
+ onOpen: () => onOpen(folder),
504
+ onToggleSelect: onToggleSelect ? (e) => onToggleSelect(folder, e) : void 0,
505
+ onCommitName: (name) => onCommitName?.(folder, name),
506
+ onCancelName
507
+ }
508
+ );
509
+ });
510
+ var PROCESSING_LABELS = {
511
+ parsing: "Parsing",
512
+ encrypting: "Encrypting",
513
+ indexing: "Indexing",
514
+ analysing: "Analysing"
515
+ };
516
+ var QUOTA_PREFIX = "QUOTA_EXCEEDED:";
517
+ function parseQuotaError(errorMessage) {
518
+ if (!errorMessage || !errorMessage.startsWith(QUOTA_PREFIX)) return null;
519
+ const body = errorMessage.slice(QUOTA_PREFIX.length);
520
+ const spend = body.match(/spend=([0-9.]+)/)?.[1];
521
+ const budget = body.match(/budget=([0-9.]+)/)?.[1];
522
+ const projectExtId = body.match(/project_ext_id=([^\s,]+)/)?.[1] ?? null;
523
+ if (spend === void 0 || budget === void 0) return null;
524
+ return { spend: Number(spend), budget: Number(budget), projectExtId };
525
+ }
526
+ function useResolvedDocStatus(doc) {
527
+ const task = useProcessingTask(doc?.external_id ?? "");
528
+ const isPendingSync = useDocumentPendingSync(doc?.external_id);
529
+ if (!doc || !doc.status) return null;
530
+ const status = resolveDocumentStatus(doc, doc.external_id ? task : void 0);
531
+ return { status, isPendingSync, failedStage: task?.failed_stage ?? doc.failed_stage ?? null };
532
+ }
533
+ var GLYPH = "size-3.5 shrink-0";
534
+ function describeGlyph(resolved, doc) {
535
+ if (resolved.isPendingSync) {
536
+ return {
537
+ node: /* @__PURE__ */ jsx(RefreshCw, { className: `${GLYPH} text-yellow-text` }),
538
+ title: "Changes saved on this device, waiting to sync"
539
+ };
540
+ }
541
+ switch (resolved.status) {
542
+ case "queued": {
543
+ const isDocx = doc.file_name?.toLowerCase().endsWith(".docx");
544
+ return {
545
+ node: /* @__PURE__ */ jsx(Clock, { className: `${GLYPH} text-muted-foreground` }),
546
+ title: isDocx ? "The document is available to edit. PDF and search indexing are processing." : "Queued, waiting to start"
547
+ };
548
+ }
549
+ case "parsing":
550
+ case "encrypting":
551
+ case "indexing":
552
+ case "analysing":
553
+ return {
554
+ node: /* @__PURE__ */ jsx(Loader2, { className: `${GLYPH} animate-spin text-ai-ink` }),
555
+ title: PROCESSING_LABELS[resolved.status]
556
+ };
557
+ case "skipped":
558
+ return {
559
+ node: /* @__PURE__ */ jsx(SkipForward, { className: `${GLYPH} text-muted-foreground` }),
560
+ title: "Skipped"
561
+ };
562
+ case "empty":
563
+ return {
564
+ node: /* @__PURE__ */ jsx(FileX, { className: `${GLYPH} text-yellow-text` }),
565
+ title: "Empty, no extractable content"
566
+ };
567
+ case "low-content":
568
+ return {
569
+ node: /* @__PURE__ */ jsx(AlertTriangle, { className: `${GLYPH} text-yellow-text` }),
570
+ title: "Low content, minimal extractable content"
571
+ };
572
+ case "failed":
573
+ if (doc.error_message?.startsWith(QUOTA_PREFIX)) {
574
+ return { node: /* @__PURE__ */ jsx(Zap, { className: `${GLYPH} text-yellow-text` }), title: "AI usage used up" };
575
+ }
576
+ return {
577
+ node: /* @__PURE__ */ jsx(
578
+ FailedStageIcon,
579
+ {
580
+ stage: resolved.failedStage,
581
+ errorMessage: doc.error_message,
582
+ className: `${GLYPH} text-red-text`
583
+ }
584
+ ),
585
+ title: "Failed"
586
+ };
587
+ default:
588
+ return null;
589
+ }
590
+ }
591
+ var DocumentStatusGlyph = memo(function DocumentStatusGlyph2({
592
+ doc
593
+ }) {
594
+ const resolved = useResolvedDocStatus(doc);
595
+ const shown = resolved ? describeGlyph(resolved, doc) : null;
596
+ if (!resolved || !shown) return null;
597
+ return /* @__PURE__ */ jsx(
598
+ "span",
599
+ {
600
+ role: "img",
601
+ "aria-label": shown.title,
602
+ title: shown.title,
603
+ "data-slot": "document-status-glyph",
604
+ "data-status": resolved.status,
605
+ className: "inline-flex items-center",
606
+ children: shown.node
607
+ }
608
+ );
609
+ });
610
+ var StatusCell2 = memo(function StatusCell3({
611
+ doc,
612
+ onStatusClick,
613
+ actions
614
+ }) {
615
+ const resolved = useResolvedDocStatus(doc);
616
+ if (!doc || !resolved) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
617
+ const { status, isPendingSync, failedStage } = resolved;
618
+ const cell = (pill) => /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center overflow-hidden", children: pill });
619
+ const click = () => onStatusClick?.();
620
+ if (isPendingSync) {
621
+ return cell(
622
+ /* @__PURE__ */ jsx(
623
+ StatusPill,
624
+ {
625
+ tone: "warning",
626
+ icon: /* @__PURE__ */ jsx(RefreshCw, { className: "size-3.5" }),
627
+ label: "Pending",
628
+ title: "Changes saved on this device \u2014 waiting to sync",
629
+ onClick: openPendingSyncDialog
630
+ }
631
+ )
632
+ );
633
+ }
634
+ switch (status) {
635
+ case "completed":
636
+ return cell(
637
+ /* @__PURE__ */ jsx(
638
+ StatusPill,
639
+ {
640
+ tone: "success",
641
+ icon: /* @__PURE__ */ jsx(CheckCircle, { className: "size-3.5" }),
642
+ label: "Ready",
643
+ title: "Ready",
644
+ onClick: click
645
+ }
646
+ )
647
+ );
648
+ case "skipped":
649
+ return cell(
650
+ /* @__PURE__ */ jsx(
651
+ StatusPill,
652
+ {
653
+ tone: "neutral",
654
+ icon: /* @__PURE__ */ jsx(SkipForward, { className: "size-3.5" }),
655
+ label: "Skipped",
656
+ title: "Skipped",
657
+ onClick: click
658
+ }
659
+ )
660
+ );
661
+ case "empty":
662
+ return cell(
663
+ /* @__PURE__ */ jsx(
664
+ StatusPill,
665
+ {
666
+ tone: "warning",
667
+ icon: /* @__PURE__ */ jsx(FileX, { className: "size-3.5" }),
668
+ label: "Empty",
669
+ title: "Empty - no extractable content",
670
+ onClick: click
671
+ }
672
+ )
673
+ );
674
+ case "low-content":
675
+ return cell(
676
+ /* @__PURE__ */ jsx(
677
+ StatusPill,
678
+ {
679
+ tone: "warning",
680
+ icon: /* @__PURE__ */ jsx(AlertTriangle, { className: "size-3.5" }),
681
+ label: "Low content",
682
+ title: "Low content - minimal extractable content",
683
+ onClick: click
684
+ }
685
+ )
686
+ );
687
+ case "failed": {
688
+ const quota = parseQuotaError(doc.error_message);
689
+ if (quota) {
690
+ return cell(
691
+ /* @__PURE__ */ jsx(
692
+ StatusPill,
693
+ {
694
+ tone: "warning",
695
+ icon: /* @__PURE__ */ jsx(Zap, { className: "size-3.5" }),
696
+ label: "Quota",
697
+ title: "AI usage used up \u2014 click for options",
698
+ onClick: () => actions?.openQuota?.(quota)
699
+ }
700
+ )
701
+ );
702
+ }
703
+ return cell(
704
+ /* @__PURE__ */ jsx(
705
+ StatusPill,
706
+ {
707
+ tone: "danger",
708
+ icon: /* @__PURE__ */ jsx(
709
+ FailedStageIcon,
710
+ {
711
+ stage: failedStage,
712
+ errorMessage: doc.error_message,
713
+ className: "size-3.5"
714
+ }
715
+ ),
716
+ label: "Failed",
717
+ onClick: click
718
+ }
719
+ )
720
+ );
721
+ }
722
+ case "queued": {
723
+ const isDocx = doc.file_name?.toLowerCase().endsWith(".docx");
724
+ return cell(
725
+ /* @__PURE__ */ jsx(
726
+ StatusPill,
727
+ {
728
+ tone: "neutral",
729
+ label: isDocx ? "Uploaded" : "Queued",
730
+ progress: "queued",
731
+ title: isDocx ? "The document is available to edit. PDF and search indexing are processing." : "Queued - waiting to start",
732
+ onClick: click
733
+ }
734
+ )
735
+ );
736
+ }
737
+ case "parsing":
738
+ case "encrypting":
739
+ case "indexing":
740
+ case "analysing":
741
+ return cell(
742
+ /* @__PURE__ */ jsx(
743
+ StatusPill,
744
+ {
745
+ tone: "info",
746
+ label: PROCESSING_LABELS[status],
747
+ progress: "processing",
748
+ title: PROCESSING_LABELS[status],
749
+ onClick: click
750
+ }
751
+ )
752
+ );
753
+ default:
754
+ return cell(/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: status }));
755
+ }
756
+ });
757
+ var UserAvatar = memo(function UserAvatar2({
758
+ user,
759
+ isMe = false,
760
+ onOpen
761
+ }) {
762
+ if (!user) return /* @__PURE__ */ jsx(UserEntity, { empty: true, size: "xs" });
763
+ const colorClass = getUserAvatarColor(user.external_id);
764
+ const agent = isAgent(user);
765
+ return /* @__PURE__ */ jsx(
766
+ UserEntity,
767
+ {
768
+ size: "xs",
769
+ variant: "icon",
770
+ showTooltip: false,
771
+ interactive: !!onOpen,
772
+ initials: getUserInitials(user),
773
+ displayName: isMe ? "You" : getUserDisplayName(user),
774
+ picture: user.picture,
775
+ colorClass,
776
+ isAgent: agent,
777
+ isVerified: user.is_identity_verified === true,
778
+ agentStyle: agent ? agentAvatarColors(colorClass) : void 0,
779
+ isMe,
780
+ onClick: onOpen ? (e) => {
781
+ e.stopPropagation();
782
+ onOpen(user.external_id);
783
+ } : void 0
784
+ }
785
+ );
786
+ });
787
+ function DocumentSummaryTooltip({
788
+ doc,
789
+ users
790
+ }) {
791
+ const { data: tags } = useTags();
792
+ const modifiedBy = users.find(
793
+ (u) => u.external_id === (doc.updated_by_ext_id ?? doc.created_by_ext_id)
794
+ );
795
+ const tagNameById = /* @__PURE__ */ new Map();
796
+ for (const tag of tags ?? []) tagNameById.set(tag.external_id, tag.name);
797
+ return /* @__PURE__ */ jsx(FileTooltipContent, { doc, modifiedBy, tagNameById });
798
+ }
799
+ var OPEN_AFTER_DOUBLE_CLICK_WINDOW_MS = 300;
800
+ var DocumentNameCell = memo(function DocumentNameCell2({
801
+ doc,
802
+ canEdit,
803
+ users,
804
+ onOpen,
805
+ onReview,
806
+ onDocumentChat,
807
+ onRename,
808
+ onDownload,
809
+ onMove,
810
+ onDelete
811
+ }) {
812
+ const arbi = useArbi();
813
+ const { notify } = useBlocksEnvironment();
814
+ const isViewing = useOpenViewerDocumentId() === doc.external_id;
815
+ const openTimerRef = useRef(void 0);
816
+ useEffect(() => () => window.clearTimeout(openTimerRef.current), []);
817
+ const downloadMarkup = async () => {
818
+ try {
819
+ const { blob, fileName } = await fetchMarkupPdf(arbi.getClient().fetch, doc.external_id);
820
+ downloadBlob(blob, fileName);
821
+ } catch (e) {
822
+ notify(e instanceof Error ? e.message : "The markup could not be downloaded", "error");
823
+ }
824
+ };
825
+ return /* @__PURE__ */ jsx(
826
+ DocumentNameCellFrame,
827
+ {
828
+ testId: `open-document-viewer-button-${doc.external_id}`,
829
+ isViewing,
830
+ subtitle: [doc.created_at?.slice(0, 10), doc.folder ? formatFolderLabel(doc.folder) : null].filter(Boolean).join(" \xB7 "),
831
+ children: /* @__PURE__ */ jsx(
832
+ DocumentEntity,
833
+ {
834
+ doc,
835
+ size: "base",
836
+ labelMaxWidth: "max-w-full",
837
+ fullWidth: true,
838
+ status: /* @__PURE__ */ jsx(DocumentStatusGlyph, { doc }),
839
+ tooltipContent: /* @__PURE__ */ jsx(DocumentSummaryTooltip, { doc, users }),
840
+ iconBadge: /* @__PURE__ */ jsx(
841
+ DocumentSyncGlyph,
842
+ {
843
+ docExtId: doc.external_id,
844
+ size: 10,
845
+ className: "absolute -bottom-1 -right-1"
846
+ }
847
+ ),
848
+ onClick: (e) => {
849
+ e.stopPropagation();
850
+ window.clearTimeout(openTimerRef.current);
851
+ if (e.detail > 1) return;
852
+ openTimerRef.current = window.setTimeout(onOpen, OPEN_AFTER_DOUBLE_CLICK_WINDOW_MS);
853
+ },
854
+ actions: /* @__PURE__ */ jsx(
855
+ DocumentRowMenu,
856
+ {
857
+ canEdit,
858
+ onOpen,
859
+ onReview,
860
+ onDocumentChat,
861
+ onRename,
862
+ onDownload,
863
+ onDownloadMarkup: currentHasMarkup(doc) ? () => void downloadMarkup() : void 0,
864
+ downloadMarkupDisabledReason: isSignedVersion(doc) ? SIGNED_LOCKED_REASON : void 0,
865
+ onMove,
866
+ onDelete
867
+ }
868
+ ),
869
+ className: "min-w-0 max-w-full border-transparent bg-transparent hover:bg-foreground/5"
870
+ }
871
+ )
872
+ }
873
+ );
874
+ });
875
+ var DocumentSharedCell = memo(function DocumentSharedCell2({
876
+ document,
877
+ disabled = false,
878
+ disabledTooltip,
879
+ onToggle
880
+ }) {
881
+ const handleToggle = useCallback(
882
+ (shouldShare) => onToggle(document.external_id, shouldShare),
883
+ [document.external_id, onToggle]
884
+ );
885
+ return /* @__PURE__ */ jsx(
886
+ SharedCell,
887
+ {
888
+ item: document,
889
+ onToggle: handleToggle,
890
+ disabled,
891
+ disabledTooltip,
892
+ tooltipActive: visibilityToggleTooltip(true),
893
+ tooltipInactive: visibilityToggleTooltip(false),
894
+ workspaceLabel: getEntityLabel("WORKSPACE")
895
+ }
896
+ );
897
+ });
898
+ function useDocumentFolders(documents, value) {
899
+ return useMemo(() => {
900
+ const paths = /* @__PURE__ */ new Set();
901
+ for (const doc of documents) if (doc.folder) paths.add(doc.folder);
902
+ if (value) paths.add(value);
903
+ return [...paths].sort((a, b) => a.localeCompare(b));
904
+ }, [documents, value]);
905
+ }
906
+ function folderSegments(folder) {
907
+ return folder.split("/").map((part, i) => i === 0 ? formatFolderSegment(part) : part).filter((part, i) => i > 0 || part !== "");
908
+ }
909
+ var DocumentFolderCell = memo(
910
+ function DocumentFolderCell2({
911
+ document,
912
+ isEditable,
913
+ allDocuments,
914
+ onUpdateFolder
915
+ }) {
916
+ const folder = document.folder;
917
+ const folders = useDocumentFolders(allDocuments, folder);
918
+ return /* @__PURE__ */ jsx(
919
+ FolderCell,
920
+ {
921
+ folder,
922
+ segments: folder ? folderSegments(folder) : [],
923
+ icon: folder && hasFolderProviderIcon(folder) ? /* @__PURE__ */ jsx(FolderProviderIcon, { folderPath: folder, className: "h-3.5 w-3.5 flex-none shrink-0" }) : void 0,
924
+ isEditable,
925
+ picker: /* @__PURE__ */ jsx(
926
+ FolderCommandList,
927
+ {
928
+ folders,
929
+ value: folder,
930
+ onSelect: (next) => onUpdateFolder(document.external_id, next),
931
+ showRemove: !!folder
932
+ }
933
+ )
934
+ }
935
+ );
936
+ },
937
+ (prev, next) => prev.document.external_id === next.document.external_id && prev.document.folder === next.document.folder && prev.isEditable === next.isEditable && prev.allDocuments === next.allDocuments && prev.onUpdateFolder === next.onUpdateFolder
938
+ );
939
+ var RELATION_LABELS = {
940
+ redaction: "Redacted copy",
941
+ annotated: "Annotated copy",
942
+ production: "Production",
943
+ crop: "Crop",
944
+ redline_base: "Redline",
945
+ redline_revised: "Redline",
946
+ translation: "Translation"
947
+ };
948
+ var relationLabel = (role, version) => {
949
+ const label = role ? RELATION_LABELS[role] : void 0;
950
+ return version ? `${label ?? "Made"} from v${version}` : label;
951
+ };
952
+ var RelatedDocumentsCell = memo(function RelatedDocumentsCell2({
953
+ currentDoc,
954
+ related,
955
+ viewingDocumentId,
956
+ onDocumentClick,
957
+ onDelete,
958
+ canDelete,
959
+ onCompare
960
+ }) {
961
+ return /* @__PURE__ */ jsx(
962
+ RelatedDocsCell,
963
+ {
964
+ parent: related.parent,
965
+ attachments: related.children,
966
+ madeFrom: related.madeFrom,
967
+ copies: related.copies,
968
+ getRelation: (doc) => relationLabel(related.roles[doc.external_id], related.versions?.[doc.external_id]),
969
+ duplicates: related.duplicates,
970
+ similar: related.similar.map(({ doc }) => doc),
971
+ renderDoc: (doc) => /* @__PURE__ */ jsx(
972
+ DocumentEntity,
973
+ {
974
+ doc,
975
+ icon: viewingDocumentId === doc.external_id ? /* @__PURE__ */ jsx(Eye, { className: "h-3.5 w-3.5 flex-shrink-0 text-primary" }) : void 0,
976
+ onClick: () => onDocumentClick(doc.external_id)
977
+ }
978
+ ),
979
+ getKey: (doc) => doc.external_id,
980
+ onSwitchTo: (doc) => {
981
+ const version = related.versions?.[doc.external_id];
982
+ onDocumentClick(version ? `${doc.external_id}@v${version}` : doc.external_id);
983
+ },
984
+ onDelete,
985
+ canDelete,
986
+ onCompare: onCompare ? (doc) => onCompare(currentDoc.external_id, doc.external_id) : void 0
987
+ }
988
+ );
989
+ });
990
+ var NOT_A_MEMBER_MESSAGE = "Join this workspace as a collaborator or owner to create or apply labels.";
991
+ var DocumentLabelsCell = memo(function DocumentLabelsCell2({
992
+ doc,
993
+ labels,
994
+ createDocTag,
995
+ deleteDocTag,
996
+ createTag,
997
+ isMember,
998
+ rowHeight,
999
+ actions
1000
+ }) {
1001
+ const isCreatingTag = useIsCreatingTag();
1002
+ const { notify } = useBlocksEnvironment();
1003
+ const options = useMemo(
1004
+ () => labels.map((t) => ({
1005
+ id: t.external_id,
1006
+ name: t.name,
1007
+ color: getEntityColor(t.external_id, "medium")
1008
+ })),
1009
+ [labels]
1010
+ );
1011
+ const appliedIds = useMemo(
1012
+ () => new Set(
1013
+ (doc.doctags || []).filter((dt) => labels.some((t) => t.external_id === dt.tag_ext_id)).map((dt) => dt.tag_ext_id)
1014
+ ),
1015
+ [doc.doctags, labels]
1016
+ );
1017
+ const applyTag = useCallback(
1018
+ (tagId) => createDocTag.mutateAsync({ tagId, docIds: [doc.external_id] }),
1019
+ [createDocTag, doc.external_id]
1020
+ );
1021
+ const handleToggle = useCallback(
1022
+ async (tagId) => {
1023
+ if (!isMember) return notify(NOT_A_MEMBER_MESSAGE, "info");
1024
+ if (appliedIds.has(tagId)) {
1025
+ await deleteDocTag.mutateAsync({ tagId, docIds: [doc.external_id] });
1026
+ } else {
1027
+ await applyTag(tagId);
1028
+ }
1029
+ },
1030
+ [isMember, appliedIds, deleteDocTag, applyTag, doc.external_id, notify]
1031
+ );
1032
+ const handleCreate = useCallback(
1033
+ async (name) => {
1034
+ const trimmed = name.trim();
1035
+ if (!trimmed) return;
1036
+ if (!isMember) return notify(NOT_A_MEMBER_MESSAGE, "info");
1037
+ const existing = labels.find((t) => t.name.toLowerCase() === trimmed.toLowerCase());
1038
+ if (existing) {
1039
+ if (!appliedIds.has(existing.external_id)) await applyTag(existing.external_id);
1040
+ return;
1041
+ }
1042
+ if (isCreatingTag(trimmed)) return;
1043
+ const created = await createTag.mutateAsync({
1044
+ name: trimmed,
1045
+ tagType: { type: "checkbox", options: [] },
1046
+ shared: false
1047
+ });
1048
+ if (created?.external_id) await applyTag(created.external_id);
1049
+ },
1050
+ [isMember, labels, appliedIds, createTag, applyTag, isCreatingTag, notify]
1051
+ );
1052
+ const openFieldsManager = actions?.openFieldsManager;
1053
+ return /* @__PURE__ */ jsx(
1054
+ LabelMultiSelectView,
1055
+ {
1056
+ options,
1057
+ appliedIds,
1058
+ onToggle: handleToggle,
1059
+ onCreate: handleCreate,
1060
+ onEditLabels: openFieldsManager ? () => openFieldsManager() : void 0,
1061
+ rowHeight
1062
+ }
1063
+ );
1064
+ });
1065
+ function DocumentUser({
1066
+ user,
1067
+ tooltip = true,
1068
+ variant = "icon"
1069
+ }) {
1070
+ const { renderUser } = useDocumentsSupport();
1071
+ const { openUser } = useDocumentHostActions();
1072
+ if (user && renderUser) return /* @__PURE__ */ jsx(Fragment, { children: renderUser(user, { tooltip, variant }) });
1073
+ if (user && variant === "pill")
1074
+ return /* @__PURE__ */ jsx(
1075
+ UserEntity,
1076
+ {
1077
+ size: "sm",
1078
+ variant: "pill",
1079
+ displayName: getUserDisplayName(user),
1080
+ picture: user.picture,
1081
+ initials: `${user.given_name?.charAt(0) ?? ""}${user.family_name?.charAt(0) ?? ""}`
1082
+ }
1083
+ );
1084
+ return /* @__PURE__ */ jsx(UserAvatar, { user, onOpen: openUser });
1085
+ }
1086
+ function useMemberLookup() {
1087
+ const { data: members = [] } = useWorkspaceUsers();
1088
+ return useCallback(
1089
+ (userId) => userId ? members.find((m) => m.user.external_id === userId)?.user : void 0,
1090
+ [members]
1091
+ );
1092
+ }
1093
+ var useFilesStore = create()(
1094
+ persist(
1095
+ (set) => ({
1096
+ pendingFolders: {},
1097
+ addPendingFolder: (workspaceId, path) => set((state) => {
1098
+ const current = state.pendingFolders[workspaceId] ?? [];
1099
+ if (current.includes(path)) return state;
1100
+ return { pendingFolders: { ...state.pendingFolders, [workspaceId]: [...current, path] } };
1101
+ }),
1102
+ removePendingFolder: (workspaceId, path) => set((state) => {
1103
+ const current = state.pendingFolders[workspaceId] ?? [];
1104
+ if (!current.includes(path)) return state;
1105
+ return {
1106
+ pendingFolders: {
1107
+ ...state.pendingFolders,
1108
+ [workspaceId]: current.filter((p) => p !== path)
1109
+ }
1110
+ };
1111
+ })
1112
+ }),
1113
+ {
1114
+ name: "arbi_explorer_pending_folders",
1115
+ storage: createJSONStorage(() => sessionStorage),
1116
+ partialize: (state) => ({ pendingFolders: state.pendingFolders })
1117
+ }
1118
+ )
1119
+ );
1120
+ var NONE = [];
1121
+ function usePendingFolders(workspaceId) {
1122
+ return useFilesStore(
1123
+ (state) => (workspaceId ? state.pendingFolders[workspaceId] : void 0) ?? NONE
1124
+ );
1125
+ }
1126
+ var FILES_PREFS_KEY = "files";
1127
+ var DEFAULT_VIEW_MODE = "explorer";
1128
+ var useFilesPrefs = create()(
1129
+ persist(
1130
+ (set) => ({
1131
+ documentFilters: {},
1132
+ setDocumentFilters: (documentFilters) => set({ documentFilters }),
1133
+ viewModes: {},
1134
+ setViewMode: (viewMode, prefsKey = FILES_PREFS_KEY) => set(
1135
+ (state) => state.viewModes[prefsKey] === viewMode ? state : { viewModes: { ...state.viewModes, [prefsKey]: viewMode } }
1136
+ ),
1137
+ // New users start at the compact minimum (more rows at once).
1138
+ rowHeight: DOCUMENTS_ROW_HEIGHT_INITIAL,
1139
+ setRowHeight: (rowHeight) => set({ rowHeight })
1140
+ }),
1141
+ {
1142
+ name: "arbi_files_prefs",
1143
+ storage: createJSONStorage(() => localStorage),
1144
+ version: 1,
1145
+ // Version 0 kept one view for every files page: it becomes the files page's own.
1146
+ migrate: (persisted, version) => {
1147
+ const state = persisted ?? {};
1148
+ if (version >= 1) return state;
1149
+ const { viewMode, ...rest } = state;
1150
+ return {
1151
+ ...rest,
1152
+ viewModes: viewMode ? { [FILES_PREFS_KEY]: viewMode } : {}
1153
+ };
1154
+ },
1155
+ partialize: (state) => ({
1156
+ documentFilters: state.documentFilters,
1157
+ viewModes: state.viewModes,
1158
+ rowHeight: state.rowHeight
1159
+ })
1160
+ }
1161
+ )
1162
+ );
1163
+ function filesViewMode(state, prefsKey = FILES_PREFS_KEY, defaultViewMode = DEFAULT_VIEW_MODE) {
1164
+ return state.viewModes[prefsKey] ?? defaultViewMode;
1165
+ }
1166
+ var useAiReviewStore = create()((set) => ({
1167
+ open: false,
1168
+ run: null,
1169
+ setOpen: (open) => set({ open }),
1170
+ setRun: (run) => set({ run }),
1171
+ markFinished: (docIds) => set((state) => {
1172
+ const run = state.run;
1173
+ if (!run) return state;
1174
+ const finished = new Set(run.finishedDocIds ?? []);
1175
+ const added = docIds.filter((id) => run.docIds.includes(id) && !finished.has(id));
1176
+ if (added.length === 0) return state;
1177
+ return { run: { ...run, finishedDocIds: [...finished, ...added] } };
1178
+ })
1179
+ }));
1180
+ var useFilesGridStates = create()(
1181
+ persist(
1182
+ (set) => ({
1183
+ gridStates: {},
1184
+ setGridState: (gridId, state) => set((current) => ({ gridStates: { ...current.gridStates, [gridId]: state } }))
1185
+ }),
1186
+ { name: "arbi_files_grids", storage: createJSONStorage(() => localStorage) }
1187
+ )
1188
+ );
1189
+ var useFilesDialogs = create()((set) => ({
1190
+ move: null,
1191
+ openMove: (folder = null) => set({ move: { folder } }),
1192
+ closeMove: () => set({ move: null }),
1193
+ bulkTagsOpen: false,
1194
+ setBulkTagsOpen: (bulkTagsOpen) => set({ bulkTagsOpen }),
1195
+ deleteRequest: null,
1196
+ requestDelete: (deleteRequest) => set({ deleteRequest }),
1197
+ exportOpen: false,
1198
+ setExportOpen: (exportOpen) => set({ exportOpen })
1199
+ }));
1200
+ function ConnectedTagEntity({
1201
+ tag,
1202
+ size = "md",
1203
+ className = "",
1204
+ onClick,
1205
+ showTooltip = true,
1206
+ canEdit = false,
1207
+ onEditClick
1208
+ }) {
1209
+ const { data: workspaceTags } = useTags();
1210
+ const { data: members = [] } = useWorkspaceUsers();
1211
+ const byId = (id) => id ? members.find((m) => m.user.external_id === id)?.user : void 0;
1212
+ const freshTag = useMemo(() => {
1213
+ if (!workspaceTags) return tag;
1214
+ const found = workspaceTags.find((t) => t.external_id === tag.external_id);
1215
+ return found || tag;
1216
+ }, [workspaceTags, tag]);
1217
+ const creator = byId(tag.created_by_ext_id) ?? null;
1218
+ const updater = byId(tag.updated_by_ext_id) ?? null;
1219
+ const Icon = getTagTypeIcon(tag.tag_type.type);
1220
+ const tagColor = getEntityColor(tag.external_id, "medium");
1221
+ const handleVisibilityToggle = () => {
1222
+ if (canEdit && onEditClick) {
1223
+ onEditClick();
1224
+ }
1225
+ };
1226
+ const tooltipContent = showTooltip ? /* @__PURE__ */ jsxs(EntityTooltip, { children: [
1227
+ /* @__PURE__ */ jsx(
1228
+ EntityTooltipHeader,
1229
+ {
1230
+ lead: /* @__PURE__ */ jsx(
1231
+ "span",
1232
+ {
1233
+ className: "inline-flex items-center justify-center rounded-md text-white p-1",
1234
+ style: { backgroundColor: tagColor },
1235
+ children: /* @__PURE__ */ jsx(Icon, { size: 16 })
1236
+ }
1237
+ ),
1238
+ title: tag.name
1239
+ }
1240
+ ),
1241
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 text-sm", children: [
1242
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1243
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Type:" }),
1244
+ /* @__PURE__ */ jsx("span", { children: getTagTypeLabel(tag.tag_type.type) })
1245
+ ] }),
1246
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1247
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Documents:" }),
1248
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "h-5 min-w-[20px] justify-center", children: freshTag.doctag_count ?? 0 })
1249
+ ] }),
1250
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1251
+ /* @__PURE__ */ jsx(
1252
+ VisibilityToggle,
1253
+ {
1254
+ items: freshTag,
1255
+ onToggle: handleVisibilityToggle,
1256
+ disabled: !canEdit,
1257
+ showLabel: false,
1258
+ showTooltip: canEdit,
1259
+ tooltipActive: "Click to edit",
1260
+ tooltipInactive: "Click to edit"
1261
+ }
1262
+ ),
1263
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: freshTag.shared ? "Shared" : "Private" })
1264
+ ] }),
1265
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1266
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Created:" }),
1267
+ /* @__PURE__ */ jsx("span", { children: formatFriendlyDate(tag.created_at) }),
1268
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "by" }),
1269
+ /* @__PURE__ */ jsx(UserAvatar, { user: creator ?? void 0 })
1270
+ ] }),
1271
+ tag.updated_at && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1272
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Updated:" }),
1273
+ /* @__PURE__ */ jsx("span", { children: formatFriendlyDate(tag.updated_at) }),
1274
+ updater && /* @__PURE__ */ jsxs(Fragment, { children: [
1275
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "by" }),
1276
+ /* @__PURE__ */ jsx(UserAvatar, { user: updater })
1277
+ ] })
1278
+ ] })
1279
+ ] })
1280
+ ] }) : void 0;
1281
+ return /* @__PURE__ */ jsx(
1282
+ TagEntity,
1283
+ {
1284
+ tag: { ...tag, color: tagColor },
1285
+ size,
1286
+ className,
1287
+ onClick,
1288
+ showTooltip,
1289
+ tooltipContent
1290
+ }
1291
+ );
1292
+ }
1293
+ function FolderPicker({
1294
+ documents,
1295
+ value,
1296
+ onSelect
1297
+ }) {
1298
+ const folders = useDocumentFolders(documents, value);
1299
+ return /* @__PURE__ */ jsx(FolderCommandList, { folders, value, onSelect, showRemove: !!value });
1300
+ }
1301
+ function RelatedDocuments({
1302
+ doc,
1303
+ related,
1304
+ onOpen,
1305
+ onDelete,
1306
+ canDelete,
1307
+ onCompare
1308
+ }) {
1309
+ const viewingDocumentId = useOpenViewerDocumentId();
1310
+ return /* @__PURE__ */ jsx(
1311
+ RelatedDocumentsCell,
1312
+ {
1313
+ currentDoc: doc,
1314
+ related,
1315
+ viewingDocumentId,
1316
+ onDocumentClick: (id) => onOpen?.(id),
1317
+ onDelete: (other) => onDelete?.(other.external_id),
1318
+ canDelete,
1319
+ onCompare
1320
+ }
1321
+ );
1322
+ }
1323
+ function DocTagAttribution({ doctag }) {
1324
+ const memberById = useMemberLookup();
1325
+ const creator = memberById(doctag.created_by_ext_id);
1326
+ const updater = doctag.updated_by_ext_id && doctag.updated_by_ext_id !== doctag.created_by_ext_id ? memberById(doctag.updated_by_ext_id) : void 0;
1327
+ const lastUser = updater || creator;
1328
+ if (!lastUser) return null;
1329
+ const lines = [
1330
+ creator && `Created ${formatFriendlyDate(doctag.created_at)} by ${creator.given_name || creator.email}`,
1331
+ updater && `Updated ${formatFriendlyDate(doctag.updated_at)} by ${updater.given_name || updater.email}`
1332
+ ].filter((line) => !!line);
1333
+ return /* @__PURE__ */ jsx(
1334
+ FieldAttribution,
1335
+ {
1336
+ avatar: /* @__PURE__ */ jsx(DocumentUser, { user: lastUser, tooltip: false }),
1337
+ date: formatFriendlyDate(updater ? doctag.updated_at : doctag.created_at),
1338
+ lines
1339
+ }
1340
+ );
1341
+ }
1342
+ function LabelsCombobox({
1343
+ labelTags,
1344
+ appliedTagIds,
1345
+ onToggle,
1346
+ onCreateAndApply
1347
+ }) {
1348
+ const options = useMemo(
1349
+ () => labelTags.map((t) => ({
1350
+ id: t.external_id,
1351
+ name: t.name,
1352
+ color: getEntityColor(t.external_id, "medium")
1353
+ })),
1354
+ [labelTags]
1355
+ );
1356
+ const handleCreate = (name) => {
1357
+ const trimmed = name.trim();
1358
+ if (!trimmed) return;
1359
+ const existing = labelTags.find((t) => t.name.toLowerCase() === trimmed.toLowerCase());
1360
+ if (!existing) onCreateAndApply?.(trimmed);
1361
+ else if (!appliedTagIds.has(existing.external_id)) onToggle(existing);
1362
+ };
1363
+ return /* @__PURE__ */ jsx(
1364
+ FieldLabelsSelect,
1365
+ {
1366
+ options,
1367
+ appliedIds: appliedTagIds,
1368
+ onToggle: (id) => {
1369
+ const tag = labelTags.find((t) => t.external_id === id);
1370
+ if (tag) onToggle(tag);
1371
+ },
1372
+ onCreate: onCreateAndApply ? handleCreate : void 0
1373
+ }
1374
+ );
1375
+ }
1376
+ var METADATA_FIELDS = {
1377
+ title: (doc) => getDocumentTitle(doc),
1378
+ doc_nature: (doc) => doc.doc_metadata?.doc_nature || "",
1379
+ doc_author: (doc) => doc.doc_metadata?.doc_author || "",
1380
+ doc_subject: (doc) => doc.doc_metadata?.doc_subject || "",
1381
+ // As the table shows it: with the time when the value has one (emails).
1382
+ doc_date: (doc) => formatDocDate(getDocumentDate(doc))
1383
+ };
1384
+ var INPUT_CLASS = "text-sm bg-muted/40 focus:bg-background transition-colors";
1385
+ var READ_ONLY_FIELDS = {
1386
+ file_name: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "strong", children: doc.file_name || "N/A" }),
1387
+ status: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.status || "N/A" }),
1388
+ n_pages: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.n_pages || "N/A" }),
1389
+ created_at: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.created_at ? formatFriendlyDate(doc.created_at) : "N/A" }),
1390
+ updated_at: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.updated_at ? formatFriendlyDate(doc.updated_at) : "N/A" }),
1391
+ file_type: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: friendlyFileType(doc.file_type, doc.file_name) }),
1392
+ file_size: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.file_size ? `${Math.round(doc.file_size / 1024)} KB` : "N/A" }),
1393
+ doc_id: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", isMono: true, children: doc.external_id || "N/A" }),
1394
+ content_hash: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", isMono: true, isTruncated: true, children: doc.content_hash || "N/A" })
1395
+ };
1396
+ function documentFieldContent(options) {
1397
+ const { columnId, doc, canEdit, workspaceTags, getColumnLabel, getColumnIcon } = options;
1398
+ const Icon = getColumnIcon(columnId);
1399
+ const standard = (children) => ({
1400
+ label: getColumnLabel(columnId),
1401
+ icon: Icon ? /* @__PURE__ */ jsx(Icon, { size: 14 }) : void 0,
1402
+ children
1403
+ });
1404
+ const metadata = METADATA_FIELDS[columnId];
1405
+ if (metadata) {
1406
+ const editable = options.isColumnEditable(columnId) && canEdit;
1407
+ return standard(
1408
+ editable ? /* @__PURE__ */ jsx(
1409
+ DebouncedInput,
1410
+ {
1411
+ value: metadata(doc),
1412
+ onChange: (value2) => options.onUpdateDocumentField(columnId, value2),
1413
+ multiline: true,
1414
+ placeholder: `Add ${getColumnLabel(columnId).toLowerCase()}\u2026`,
1415
+ className: INPUT_CLASS
1416
+ }
1417
+ ) : /* @__PURE__ */ jsx(FieldValue, { children: metadata(doc) || "N/A" })
1418
+ );
1419
+ }
1420
+ const readOnly = READ_ONLY_FIELDS[columnId];
1421
+ if (readOnly) return standard(readOnly(doc));
1422
+ if (columnId === "created_by") return standard(/* @__PURE__ */ jsx(DocumentUser, { user: options.creator }));
1423
+ if (columnId === "folder") {
1424
+ return standard(
1425
+ canEdit ? /* @__PURE__ */ jsx(
1426
+ FieldFolderSelect,
1427
+ {
1428
+ folder: doc.folder,
1429
+ picker: /* @__PURE__ */ jsx(
1430
+ FolderPicker,
1431
+ {
1432
+ documents: options.allDocuments ?? [],
1433
+ value: doc.folder,
1434
+ onSelect: (folder) => options.onUpdateDocumentField("folder", folder)
1435
+ }
1436
+ )
1437
+ }
1438
+ ) : /* @__PURE__ */ jsx(FieldFolderValue, { folder: doc.folder })
1439
+ );
1440
+ }
1441
+ if (columnId === "related") {
1442
+ const related = options.relatedDocs;
1443
+ if (!related) return null;
1444
+ return standard(
1445
+ /* @__PURE__ */ jsx(
1446
+ RelatedDocuments,
1447
+ {
1448
+ doc,
1449
+ related,
1450
+ onOpen: options.onOpenDocument,
1451
+ onDelete: options.onDeleteDocument,
1452
+ canDelete: options.canDeleteRelatedDocument,
1453
+ onCompare: options.onCompareDocuments
1454
+ }
1455
+ )
1456
+ );
1457
+ }
1458
+ if (columnId === "all_tags") {
1459
+ const labelTags = workspaceTags.filter(isLabelTag);
1460
+ const appliedIds = new Set(
1461
+ (doc.doctags ?? []).filter((dt) => labelTags.some((t) => t.external_id === dt.tag_ext_id)).map((dt) => dt.tag_ext_id)
1462
+ );
1463
+ return standard(
1464
+ /* @__PURE__ */ jsx(
1465
+ LabelsCombobox,
1466
+ {
1467
+ labelTags,
1468
+ appliedTagIds: appliedIds,
1469
+ onToggle: (tag2) => options.onUpdateTagValue(tag2, !appliedIds.has(tag2.external_id)),
1470
+ onCreateAndApply: options.onCreateAndApplyLabel
1471
+ }
1472
+ )
1473
+ );
1474
+ }
1475
+ const tag = workspaceTags.find((t) => t.external_id === columnId);
1476
+ if (!tag || !isAnnotationTag(tag)) return null;
1477
+ const doctag = doc.doctags?.find((dt) => dt.tag_ext_id === tag.external_id);
1478
+ let value;
1479
+ if (tag.tag_type.type === "select") {
1480
+ value = /* @__PURE__ */ jsx(
1481
+ FieldNativeSelect,
1482
+ {
1483
+ value: doctag?.note || "",
1484
+ options: tag.tag_type.options,
1485
+ onChange: (next) => options.onUpdateTagValue(tag, next),
1486
+ ariaLabel: tag.name
1487
+ }
1488
+ );
1489
+ } else if (tag.tag_type.type === "number") {
1490
+ value = /* @__PURE__ */ jsx(
1491
+ DebouncedInput,
1492
+ {
1493
+ type: "number",
1494
+ value: doctag?.note || "",
1495
+ onChange: (next) => options.onUpdateTagValue(tag, next),
1496
+ placeholder: `Add ${tag.name.toLowerCase()}\u2026`,
1497
+ className: INPUT_CLASS
1498
+ }
1499
+ );
1500
+ } else {
1501
+ value = /* @__PURE__ */ jsx(
1502
+ Textarea,
1503
+ {
1504
+ value: doctag?.note || "",
1505
+ onChange: (e) => options.onUpdateTagWithCitations(tag, e.target.value, doctag?.citations ?? null),
1506
+ placeholder: "Add a note...",
1507
+ rows: 2,
1508
+ className: INPUT_CLASS
1509
+ }
1510
+ );
1511
+ }
1512
+ return {
1513
+ label: tag.name,
1514
+ tag,
1515
+ children: doctag ? /* @__PURE__ */ jsx(FieldWithAttribution, { attribution: /* @__PURE__ */ jsx(DocTagAttribution, { doctag }), children: value }) : value
1516
+ };
1517
+ }
1518
+
1519
+ export { ConnectedPendingSyncDialog, ConnectedTagEntity, DocumentFolderCell, DocumentLabelsCell, DocumentNameCell, DocumentSharedCell, DocumentStatusGlyph, DocumentSyncGlyph, DocumentUser, FILES_PREFS_KEY, FileTile, FileTooltipContent, FolderTile, RelatedDocumentsCell, StatusCell2 as StatusCell, UserAvatar, documentFieldContent, filesViewMode, isActiveDocumentStatus, openPendingSyncDialog, parseQuotaError, startMenuItem, useAiReviewStore, useDocumentFolders, useFilesDialogs, useFilesGridStates, useFilesPrefs, useFilesStore, useMemberLookup, usePendingFolders, useResolvedDocStatus };
1520
+ //# sourceMappingURL=chunk-3Y4UTPCD.js.map
1521
+ //# sourceMappingURL=chunk-3Y4UTPCD.js.map