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