@arbidocs/blocks 0.5.120 → 0.5.121
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ClippingMediaViewer-B6WG7Q64.cjs +156 -0
- package/dist/ClippingMediaViewer-B6WG7Q64.cjs.map +1 -0
- package/dist/ClippingPdfViewer-6GCVTV3V.cjs +79 -0
- package/dist/ClippingPdfViewer-6GCVTV3V.cjs.map +1 -0
- package/dist/{ConnectedCallDock-WER7R222.cjs → ConnectedCallDock-DC5V5OUJ.cjs} +25 -23
- package/dist/ConnectedCallDock-DC5V5OUJ.cjs.map +1 -0
- package/dist/{ConnectedCallRoom-T7OBQTYP.cjs → ConnectedCallRoom-FQLXWTFB.cjs} +18 -16
- package/dist/{ConnectedCallRoom-T7OBQTYP.cjs.map → ConnectedCallRoom-FQLXWTFB.cjs.map} +1 -1
- package/dist/{ConnectedNativeDocxComparison-SGE4R3M4.cjs → ConnectedNativeDocxComparison-4Q5S7VLD.cjs} +17 -17
- package/dist/{ConnectedNativeDocxComparison-SGE4R3M4.cjs.map → ConnectedNativeDocxComparison-4Q5S7VLD.cjs.map} +1 -1
- package/dist/ConnectedPresentation-4HLDZDWV.cjs +183 -0
- package/dist/ConnectedPresentation-4HLDZDWV.cjs.map +1 -0
- package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
- package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
- package/dist/ConnectedSlidesTab-7QDE2CZD.cjs +234 -0
- package/dist/ConnectedSlidesTab-7QDE2CZD.cjs.map +1 -0
- package/dist/{ConnectedStreamedWordArtifact-6MCLJRIT.cjs → ConnectedStreamedWordArtifact-FFOQJBOI.cjs} +17 -17
- package/dist/{ConnectedStreamedWordArtifact-6MCLJRIT.cjs.map → ConnectedStreamedWordArtifact-FFOQJBOI.cjs.map} +1 -1
- package/dist/{DocumentReviewCard-BPIAJJED.cjs → DocumentReviewCard-SNWVEZ7S.cjs} +17 -16
- package/dist/DocumentReviewCard-SNWVEZ7S.cjs.map +1 -0
- package/dist/{FilesViewerDialog-67WK3TZC.cjs → FilesViewerDialog-IZI63FOV.cjs} +52 -45
- package/dist/FilesViewerDialog-IZI63FOV.cjs.map +1 -0
- package/dist/{GridViewImpl-ZMJJWTOM.cjs → GridViewImpl-LTYET77Q.cjs} +3 -3
- package/dist/GridViewImpl-LTYET77Q.cjs.map +1 -0
- package/dist/{WorkspaceTableView-J3C6VH4T.cjs → WorkspaceTableView-TEIRB6VJ.cjs} +11 -10
- package/dist/WorkspaceTableView-TEIRB6VJ.cjs.map +1 -0
- package/dist/agents/index.cjs +297 -297
- package/dist/{ai-IM4A23YT.cjs → ai-KBYNRNZ6.cjs} +28 -26
- package/dist/ai-KBYNRNZ6.cjs.map +1 -0
- package/dist/calls/connected/CallControls.d.ts +2 -0
- package/dist/calls/connected/CallControls.js +71 -9
- package/dist/calls/connected/CallControls.js.map +2 -2
- package/dist/calls/connected/ShareDocumentDialog.d.ts +14 -0
- package/dist/calls/connected/ShareDocumentDialog.js +77 -0
- package/dist/calls/connected/ShareDocumentDialog.js.map +7 -0
- package/dist/calls/index.cjs +121 -121
- package/dist/chat/index.cjs +9 -8
- package/dist/{chunk-T23UTIRI.cjs → chunk-2PZT3J34.cjs} +6 -6
- package/dist/{chunk-T23UTIRI.cjs.map → chunk-2PZT3J34.cjs.map} +1 -1
- package/dist/{chunk-SGYSDABK.cjs → chunk-2W5E62EY.cjs} +6 -6
- package/dist/{chunk-SGYSDABK.cjs.map → chunk-2W5E62EY.cjs.map} +1 -1
- package/dist/{chunk-TDO5UWXF.cjs → chunk-3SCNXNHI.cjs} +5 -5
- package/dist/{chunk-TDO5UWXF.cjs.map → chunk-3SCNXNHI.cjs.map} +1 -1
- package/dist/{chunk-KTQOGT2L.cjs → chunk-474GPLCM.cjs} +7 -7
- package/dist/{chunk-KTQOGT2L.cjs.map → chunk-474GPLCM.cjs.map} +1 -1
- package/dist/{chunk-TP5PGWIO.cjs → chunk-4IOYQLKG.cjs} +3 -3
- package/dist/{chunk-TP5PGWIO.cjs.map → chunk-4IOYQLKG.cjs.map} +1 -1
- package/dist/{chunk-NY3YUCOW.cjs → chunk-4NPCDS2X.cjs} +3 -3
- package/dist/{chunk-NY3YUCOW.cjs.map → chunk-4NPCDS2X.cjs.map} +1 -1
- package/dist/{chunk-HA66DHW6.cjs → chunk-4RBQ44RY.cjs} +28 -28
- package/dist/chunk-4RBQ44RY.cjs.map +1 -0
- package/dist/{chunk-BQ5RIWWT.cjs → chunk-4VZZWYEC.cjs} +3 -3
- package/dist/{chunk-BQ5RIWWT.cjs.map → chunk-4VZZWYEC.cjs.map} +1 -1
- package/dist/{chunk-BP3IJ34D.cjs → chunk-52KGMAO5.cjs} +15 -15
- package/dist/{chunk-BP3IJ34D.cjs.map → chunk-52KGMAO5.cjs.map} +1 -1
- package/dist/{chunk-5IZFSAEZ.cjs → chunk-5534FYXP.cjs} +4 -4
- package/dist/{chunk-5IZFSAEZ.cjs.map → chunk-5534FYXP.cjs.map} +1 -1
- package/dist/chunk-5GCCUXMT.cjs +63 -0
- package/dist/chunk-5GCCUXMT.cjs.map +1 -0
- package/dist/chunk-5LTIZ44D.cjs +95 -0
- package/dist/chunk-5LTIZ44D.cjs.map +1 -0
- package/dist/{chunk-DFBDQKGE.cjs → chunk-734NPQNR.cjs} +4 -4
- package/dist/{chunk-DFBDQKGE.cjs.map → chunk-734NPQNR.cjs.map} +1 -1
- package/dist/{chunk-X36UR4A7.cjs → chunk-7VUJGHMY.cjs} +323 -96
- package/dist/chunk-7VUJGHMY.cjs.map +1 -0
- package/dist/chunk-AFQTQC7A.cjs +35 -0
- package/dist/chunk-AFQTQC7A.cjs.map +1 -0
- package/dist/{chunk-YYSBWMDJ.cjs → chunk-AY6EZSZB.cjs} +4 -4
- package/dist/{chunk-YYSBWMDJ.cjs.map → chunk-AY6EZSZB.cjs.map} +1 -1
- package/dist/{chunk-BUVIBHFU.cjs → chunk-BVAT4EVC.cjs} +38 -38
- package/dist/chunk-BVAT4EVC.cjs.map +1 -0
- package/dist/{chunk-ECLUFKYR.cjs → chunk-C2OICDMI.cjs} +10 -10
- package/dist/{chunk-ECLUFKYR.cjs.map → chunk-C2OICDMI.cjs.map} +1 -1
- package/dist/{chunk-CPR6EHG7.cjs → chunk-DR2AH7JL.cjs} +179 -55
- package/dist/chunk-DR2AH7JL.cjs.map +1 -0
- package/dist/{chunk-NJCK6V6U.cjs → chunk-EATIFPKP.cjs} +4 -60
- package/dist/chunk-EATIFPKP.cjs.map +1 -0
- package/dist/{chunk-B3LZITVF.cjs → chunk-EHP6OH5D.cjs} +11 -451
- package/dist/chunk-EHP6OH5D.cjs.map +1 -0
- package/dist/{chunk-775S43W7.cjs → chunk-ENGL7P3I.cjs} +31 -31
- package/dist/{chunk-775S43W7.cjs.map → chunk-ENGL7P3I.cjs.map} +1 -1
- package/dist/{chunk-VZCPMXWC.cjs → chunk-FKFQCK3C.cjs} +4 -4
- package/dist/{chunk-VZCPMXWC.cjs.map → chunk-FKFQCK3C.cjs.map} +1 -1
- package/dist/{chunk-6UTKM5AB.cjs → chunk-GKVE5JGB.cjs} +76 -76
- package/dist/chunk-GKVE5JGB.cjs.map +1 -0
- package/dist/{chunk-Q6CLWOP2.cjs → chunk-GPX5VC57.cjs} +50 -50
- package/dist/{chunk-Q6CLWOP2.cjs.map → chunk-GPX5VC57.cjs.map} +1 -1
- package/dist/{chunk-WAV762GP.cjs → chunk-GQXPNIRE.cjs} +6 -6
- package/dist/{chunk-WAV762GP.cjs.map → chunk-GQXPNIRE.cjs.map} +1 -1
- package/dist/chunk-GX2EBMJW.cjs +133 -0
- package/dist/chunk-GX2EBMJW.cjs.map +1 -0
- package/dist/{chunk-7OPOPYV6.cjs → chunk-H5OLHP2U.cjs} +3 -3
- package/dist/{chunk-7OPOPYV6.cjs.map → chunk-H5OLHP2U.cjs.map} +1 -1
- package/dist/chunk-HYUKPHCT.cjs +66 -0
- package/dist/chunk-HYUKPHCT.cjs.map +1 -0
- package/dist/{chunk-NLSWDP42.cjs → chunk-JQLWKNJO.cjs} +22 -12
- package/dist/chunk-JQLWKNJO.cjs.map +1 -0
- package/dist/{chunk-CKCG4NDB.cjs → chunk-JZEYHDWJ.cjs} +75 -75
- package/dist/{chunk-CKCG4NDB.cjs.map → chunk-JZEYHDWJ.cjs.map} +1 -1
- package/dist/{chunk-PGJYD67F.cjs → chunk-KNGZZC4O.cjs} +7 -6
- package/dist/chunk-KNGZZC4O.cjs.map +1 -0
- package/dist/{chunk-W6INT5GS.cjs → chunk-KP5AITQ4.cjs} +10 -10
- package/dist/{chunk-W6INT5GS.cjs.map → chunk-KP5AITQ4.cjs.map} +1 -1
- package/dist/{chunk-YYPZOEED.cjs → chunk-LHWOKOMP.cjs} +23 -2
- package/dist/chunk-LHWOKOMP.cjs.map +1 -0
- package/dist/{chunk-WXUU3COI.cjs → chunk-MZ2KZXNU.cjs} +3 -3
- package/dist/{chunk-WXUU3COI.cjs.map → chunk-MZ2KZXNU.cjs.map} +1 -1
- package/dist/chunk-NAJN32MF.cjs +154 -0
- package/dist/chunk-NAJN32MF.cjs.map +1 -0
- package/dist/{chunk-557MJ4IH.cjs → chunk-NLOETJCB.cjs} +17 -154
- package/dist/chunk-NLOETJCB.cjs.map +1 -0
- package/dist/{chunk-4XJEHKVZ.cjs → chunk-PIYYBPHH.cjs} +4 -4
- package/dist/{chunk-4XJEHKVZ.cjs.map → chunk-PIYYBPHH.cjs.map} +1 -1
- package/dist/chunk-Q3XJUXID.cjs +4774 -0
- package/dist/chunk-Q3XJUXID.cjs.map +1 -0
- package/dist/{chunk-325GVZE6.cjs → chunk-Q6DQGGP4.cjs} +3 -3
- package/dist/{chunk-325GVZE6.cjs.map → chunk-Q6DQGGP4.cjs.map} +1 -1
- package/dist/chunk-QFXILJMJ.cjs +458 -0
- package/dist/chunk-QFXILJMJ.cjs.map +1 -0
- package/dist/{chunk-QQWHG3KF.cjs → chunk-RYVZDFVO.cjs} +5 -5
- package/dist/{chunk-QQWHG3KF.cjs.map → chunk-RYVZDFVO.cjs.map} +1 -1
- package/dist/{chunk-EOG6OT5I.cjs → chunk-TXP2N3DC.cjs} +4 -4
- package/dist/{chunk-EOG6OT5I.cjs.map → chunk-TXP2N3DC.cjs.map} +1 -1
- package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
- package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
- package/dist/chunk-VJ5ZLRBD.cjs +27 -0
- package/dist/chunk-VJ5ZLRBD.cjs.map +1 -0
- package/dist/{chunk-3GWWOYGS.cjs → chunk-W6B3RYTX.cjs} +4 -4
- package/dist/{chunk-3GWWOYGS.cjs.map → chunk-W6B3RYTX.cjs.map} +1 -1
- package/dist/chunk-WOOOMTTA.cjs +19 -0
- package/dist/chunk-WOOOMTTA.cjs.map +1 -0
- package/dist/{chunk-CJYWHUZR.cjs → chunk-XCKHOXRP.cjs} +4 -4
- package/dist/{chunk-CJYWHUZR.cjs.map → chunk-XCKHOXRP.cjs.map} +1 -1
- package/dist/{chunk-6WMMZLEV.cjs → chunk-XJEXFEWG.cjs} +2 -27
- package/dist/chunk-XJEXFEWG.cjs.map +1 -0
- package/dist/chunk-XK4TVJKD.cjs +73 -0
- package/dist/chunk-XK4TVJKD.cjs.map +1 -0
- package/dist/chunk-XTR26TNE.cjs +1358 -0
- package/dist/chunk-XTR26TNE.cjs.map +1 -0
- package/dist/{chunk-E7TE2WVT.cjs → chunk-ZVEW3JBT.cjs} +3 -3
- package/dist/{chunk-E7TE2WVT.cjs.map → chunk-ZVEW3JBT.cjs.map} +1 -1
- package/dist/collaboration/index.cjs +70 -70
- package/dist/components/ZoomSlider.d.ts +25 -0
- package/dist/components/ZoomSlider.js +59 -0
- package/dist/components/ZoomSlider.js.map +7 -0
- package/dist/connect/docx.cjs +20 -20
- package/dist/connect/index.cjs +1150 -1232
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/viewer.cjs +40 -34
- package/dist/connection/ai.d.ts +1 -1
- package/dist/connection/files/ConnectedNewFileMenu.d.ts +2 -1
- package/dist/connection/files/ConnectedNewFileMenu.js +9 -3
- package/dist/connection/files/ConnectedNewFileMenu.js.map +2 -2
- package/dist/connection/files/explorer/ConnectedFilesExplorer.js +1 -1
- package/dist/connection/files/explorer/ConnectedFilesExplorer.js.map +2 -2
- package/dist/connection/files/explorer/FileTiles.js +1 -1
- package/dist/connection/files/explorer/FileTiles.js.map +2 -2
- package/dist/connection/files/fields/documentField.js +1 -1
- package/dist/connection/files/fields/documentField.js.map +2 -2
- package/dist/connection/files/grid/documentColumns.js +1 -1
- package/dist/connection/files/grid/documentColumns.js.map +2 -2
- package/dist/connection/files/page/DocumentsFilterBarActions.js +17 -28
- package/dist/connection/files/page/DocumentsFilterBarActions.js.map +2 -2
- package/dist/connection/mail/useMailboxDefaults.js +1 -1
- package/dist/connection/mail/useMailboxDefaults.js.map +2 -2
- package/dist/connection/panels/useSessionPanelMode.js +3 -2
- package/dist/connection/panels/useSessionPanelMode.js.map +2 -2
- package/dist/connection/presentation/ClippingMediaViewer.d.ts +12 -0
- package/dist/connection/presentation/ClippingMediaViewer.js +153 -0
- package/dist/connection/presentation/ClippingMediaViewer.js.map +7 -0
- package/dist/connection/presentation/ClippingPdfViewer.d.ts +22 -0
- package/dist/connection/presentation/ClippingPdfViewer.js +75 -0
- package/dist/connection/presentation/ClippingPdfViewer.js.map +7 -0
- package/dist/connection/presentation/ConnectedPresentation.d.ts +12 -0
- package/dist/connection/presentation/ConnectedPresentation.js +100 -0
- package/dist/connection/presentation/ConnectedPresentation.js.map +7 -0
- package/dist/connection/presentation/ConnectedSlidesTab.d.ts +20 -0
- package/dist/connection/presentation/ConnectedSlidesTab.js +220 -0
- package/dist/connection/presentation/ConnectedSlidesTab.js.map +7 -0
- package/dist/connection/presentation/CropClipDialog.d.ts +11 -0
- package/dist/connection/presentation/CropClipDialog.js +86 -0
- package/dist/connection/presentation/CropClipDialog.js.map +7 -0
- package/dist/connection/presentation/GenerateTile.d.ts +4 -0
- package/dist/connection/presentation/GenerateTile.js +24 -0
- package/dist/connection/presentation/GenerateTile.js.map +7 -0
- package/dist/connection/presentation/LabelColumnMenu.d.ts +8 -0
- package/dist/connection/presentation/LabelColumnMenu.js +38 -0
- package/dist/connection/presentation/LabelColumnMenu.js.map +7 -0
- package/dist/connection/presentation/PresentationDialogs.d.ts +39 -0
- package/dist/connection/presentation/PresentationDialogs.js +295 -0
- package/dist/connection/presentation/PresentationDialogs.js.map +7 -0
- package/dist/connection/presentation/PresentationFileCard.d.ts +10 -0
- package/dist/connection/presentation/PresentationFileCard.js +35 -0
- package/dist/connection/presentation/PresentationFileCard.js.map +7 -0
- package/dist/connection/presentation/PresentationPill.d.ts +8 -0
- package/dist/connection/presentation/PresentationPill.js +44 -0
- package/dist/connection/presentation/PresentationPill.js.map +7 -0
- package/dist/connection/presentation/PresentationSlot.d.ts +7 -0
- package/dist/connection/presentation/PresentationSlot.js +35 -0
- package/dist/connection/presentation/PresentationSlot.js.map +7 -0
- package/dist/connection/presentation/requests.d.ts +16 -0
- package/dist/connection/presentation/requests.js +20 -0
- package/dist/connection/presentation/requests.js.map +7 -0
- package/dist/connection/presentation/useImageGeneration.d.ts +11 -0
- package/dist/connection/presentation/useImageGeneration.js +66 -0
- package/dist/connection/presentation/useImageGeneration.js.map +7 -0
- package/dist/connection/presentation/useLabelColumns.d.ts +15 -0
- package/dist/connection/presentation/useLabelColumns.js +33 -0
- package/dist/connection/presentation/useLabelColumns.js.map +7 -0
- package/dist/connection/presentation/usePresentationController.d.ts +15 -0
- package/dist/connection/presentation/usePresentationController.js +118 -0
- package/dist/connection/presentation/usePresentationController.js.map +7 -0
- package/dist/connection/presentation/usePresentationFiles.d.ts +44 -0
- package/dist/connection/presentation/usePresentationFiles.js +307 -0
- package/dist/connection/presentation/usePresentationFiles.js.map +7 -0
- package/dist/connection/presentation/useViewerClipping.d.ts +14 -0
- package/dist/connection/presentation/useViewerClipping.js +18 -0
- package/dist/connection/presentation/useViewerClipping.js.map +7 -0
- package/dist/connection/shell/ConnectedAppShell.js +5 -1
- package/dist/connection/shell/ConnectedAppShell.js.map +2 -2
- package/dist/connection/viewer/CleanViewControl.d.ts +8 -0
- package/dist/connection/viewer/CleanViewControl.js +76 -0
- package/dist/connection/viewer/CleanViewControl.js.map +7 -0
- package/dist/connection/viewer/ConnectedDocumentViewer.js +28 -29
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/ViewerCropModal.d.ts +5 -0
- package/dist/connection/viewer/ViewerCropModal.js +22 -0
- package/dist/connection/viewer/ViewerCropModal.js.map +7 -0
- package/dist/connection/viewer/ViewerPdfPane.d.ts +3 -1
- package/dist/connection/viewer/ViewerPdfPane.js +37 -0
- package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
- package/dist/connection/viewer/drafts.js +6 -4
- package/dist/connection/viewer/drafts.js.map +2 -2
- package/dist/connection/viewer/shareDocument.d.ts +11 -0
- package/dist/connection/viewer/shareDocument.js +11 -0
- package/dist/connection/viewer/shareDocument.js.map +7 -0
- package/dist/connection/viewer/slidesTabChunk.d.ts +2 -0
- package/dist/connection/viewer/slidesTabChunk.js +9 -0
- package/dist/connection/viewer/slidesTabChunk.js.map +7 -0
- package/dist/connection/viewer/useCleanView.d.ts +14 -0
- package/dist/connection/viewer/useCleanView.js +29 -0
- package/dist/connection/viewer/useCleanView.js.map +7 -0
- package/dist/connection/viewer/useViewedDocument.d.ts +1 -0
- package/dist/connection/viewer/useViewedDocument.js +9 -1
- package/dist/connection/viewer/useViewedDocument.js.map +2 -2
- package/dist/connection/viewer/useViewerTabs.js +18 -4
- package/dist/connection/viewer/useViewerTabs.js.map +2 -2
- package/dist/connection/workflows/ConnectedWorkflowStart.d.ts +14 -2
- package/dist/connection/workflows/ConnectedWorkflowStart.js +5 -2
- package/dist/connection/workflows/ConnectedWorkflowStart.js.map +2 -2
- package/dist/dashboards/index.cjs +1 -1
- package/dist/databases/index.cjs +49 -49
- package/dist/document-tools/DocumentToolButtons.d.ts +2 -0
- package/dist/document-tools/DocumentToolButtons.js +22 -1
- package/dist/document-tools/DocumentToolButtons.js.map +2 -2
- package/dist/document-tools/index.cjs +16 -12
- package/dist/document-tools/index.d.ts +1 -1
- package/dist/document-tools/index.js +2 -0
- package/dist/document-tools/index.js.map +2 -2
- package/dist/embed/index.cjs +41 -39
- package/dist/files/GridViewImpl.js +1 -1
- package/dist/files/GridViewImpl.js.map +2 -2
- package/dist/files/ViewerChrome.d.ts +5 -1
- package/dist/files/ViewerChrome.js +16 -6
- package/dist/files/ViewerChrome.js.map +2 -2
- package/dist/files/index.cjs +225 -225
- package/dist/files/navigator/DocumentSearchList.js +1 -1
- package/dist/files/navigator/DocumentSearchList.js.map +2 -2
- package/dist/index.cjs +1666 -1664
- package/dist/index.cjs.map +1 -1
- package/dist/presentation/BoxActionBar.d.ts +11 -0
- package/dist/presentation/BoxActionBar.js +182 -0
- package/dist/presentation/BoxActionBar.js.map +7 -0
- package/dist/presentation/ClipActionBar.d.ts +26 -0
- package/dist/presentation/ClipActionBar.js +103 -0
- package/dist/presentation/ClipActionBar.js.map +7 -0
- package/dist/presentation/ClipCaptureOverlay.d.ts +14 -0
- package/dist/presentation/ClipCaptureOverlay.js +69 -0
- package/dist/presentation/ClipCaptureOverlay.js.map +7 -0
- package/dist/presentation/ClipImage.d.ts +21 -0
- package/dist/presentation/ClipImage.js +119 -0
- package/dist/presentation/ClipImage.js.map +7 -0
- package/dist/presentation/ClipTray.d.ts +11 -0
- package/dist/presentation/ClipTray.js +152 -0
- package/dist/presentation/ClipTray.js.map +7 -0
- package/dist/presentation/ClipViewControls.d.ts +11 -0
- package/dist/presentation/ClipViewControls.js +142 -0
- package/dist/presentation/ClipViewControls.js.map +7 -0
- package/dist/presentation/DesignMenu.d.ts +8 -0
- package/dist/presentation/DesignMenu.js +199 -0
- package/dist/presentation/DesignMenu.js.map +7 -0
- package/dist/presentation/LayoutMenu.d.ts +17 -0
- package/dist/presentation/LayoutMenu.js +122 -0
- package/dist/presentation/LayoutMenu.js.map +7 -0
- package/dist/presentation/MediaClip.d.ts +15 -0
- package/dist/presentation/MediaClip.js +67 -0
- package/dist/presentation/MediaClip.js.map +7 -0
- package/dist/presentation/Notice.d.ts +6 -0
- package/dist/presentation/Notice.js +43 -0
- package/dist/presentation/Notice.js.map +7 -0
- package/dist/presentation/PresentationStage.d.ts +32 -0
- package/dist/presentation/PresentationStage.js +232 -0
- package/dist/presentation/PresentationStage.js.map +7 -0
- package/dist/presentation/PresenterView.d.ts +16 -0
- package/dist/presentation/PresenterView.js +69 -0
- package/dist/presentation/PresenterView.js.map +7 -0
- package/dist/presentation/SlideDecor.d.ts +25 -0
- package/dist/presentation/SlideDecor.js +189 -0
- package/dist/presentation/SlideDecor.js.map +7 -0
- package/dist/presentation/SlidesEditor.d.ts +25 -0
- package/dist/presentation/SlidesEditor.js +359 -0
- package/dist/presentation/SlidesEditor.js.map +7 -0
- package/dist/presentation/StageBox.d.ts +30 -0
- package/dist/presentation/StageBox.js +281 -0
- package/dist/presentation/StageBox.js.map +7 -0
- package/dist/presentation/StageItem.d.ts +37 -0
- package/dist/presentation/StageItem.js +211 -0
- package/dist/presentation/StageItem.js.map +7 -0
- package/dist/presentation/box-style.d.ts +6 -0
- package/dist/presentation/box-style.js +19 -0
- package/dist/presentation/box-style.js.map +7 -0
- package/dist/presentation/boxes.d.ts +105 -0
- package/dist/presentation/boxes.js +103 -0
- package/dist/presentation/boxes.js.map +7 -0
- package/dist/presentation/draw-boxes.d.ts +8 -0
- package/dist/presentation/draw-boxes.js +130 -0
- package/dist/presentation/draw-boxes.js.map +7 -0
- package/dist/presentation/export-boxes.d.ts +10 -0
- package/dist/presentation/export-boxes.js +74 -0
- package/dist/presentation/export-boxes.js.map +7 -0
- package/dist/presentation/export-pptx.d.ts +16 -0
- package/dist/presentation/export-pptx.js +194 -0
- package/dist/presentation/export-pptx.js.map +7 -0
- package/dist/presentation/import-pptx.d.ts +35 -0
- package/dist/presentation/import-pptx.js +659 -0
- package/dist/presentation/import-pptx.js.map +7 -0
- package/dist/presentation/merge-outside-edits.d.ts +12 -0
- package/dist/presentation/merge-outside-edits.js +35 -0
- package/dist/presentation/merge-outside-edits.js.map +7 -0
- package/dist/presentation/model.d.ts +201 -0
- package/dist/presentation/model.js +271 -0
- package/dist/presentation/model.js.map +7 -0
- package/dist/presentation/panel-id.d.ts +34 -0
- package/dist/presentation/panel-id.js +24 -0
- package/dist/presentation/panel-id.js.map +7 -0
- package/dist/presentation/persistence.d.ts +121 -0
- package/dist/presentation/persistence.js +141 -0
- package/dist/presentation/persistence.js.map +7 -0
- package/dist/presentation/pptx-data.d.ts +22 -0
- package/dist/presentation/pptx-data.js +83 -0
- package/dist/presentation/pptx-data.js.map +7 -0
- package/dist/presentation/pptx-xml.d.ts +90 -0
- package/dist/presentation/pptx-xml.js +333 -0
- package/dist/presentation/pptx-xml.js.map +7 -0
- package/dist/presentation/render-slides.d.ts +58 -0
- package/dist/presentation/render-slides.js +309 -0
- package/dist/presentation/render-slides.js.map +7 -0
- package/dist/presentation/saved-boxes.d.ts +11 -0
- package/dist/presentation/saved-boxes.js +80 -0
- package/dist/presentation/saved-boxes.js.map +7 -0
- package/dist/presentation/slide-layout.d.ts +54 -0
- package/dist/presentation/slide-layout.js +117 -0
- package/dist/presentation/slide-layout.js.map +7 -0
- package/dist/presentation/stage-videos.d.ts +5 -0
- package/dist/presentation/stage-videos.js +19 -0
- package/dist/presentation/stage-videos.js.map +7 -0
- package/dist/presentation/store.d.ts +203 -0
- package/dist/presentation/store.js +429 -0
- package/dist/presentation/store.js.map +7 -0
- package/dist/presentation/theme.d.ts +102 -0
- package/dist/presentation/theme.js +276 -0
- package/dist/presentation/theme.js.map +7 -0
- package/dist/presentation/useClipDrag.d.ts +26 -0
- package/dist/presentation/useClipDrag.js +65 -0
- package/dist/presentation/useClipDrag.js.map +7 -0
- package/dist/presentation/useObjectUrl.d.ts +6 -0
- package/dist/presentation/useObjectUrl.js +15 -0
- package/dist/presentation/useObjectUrl.js.map +7 -0
- package/dist/presentation/usePresenterKeys.d.ts +13 -0
- package/dist/presentation/usePresenterKeys.js +62 -0
- package/dist/presentation/usePresenterKeys.js.map +7 -0
- package/dist/settings/index.cjs +151 -150
- package/dist/shell/PanelPortal.js +1 -0
- package/dist/shell/PanelPortal.js.map +2 -2
- package/dist/shell/index.cjs +112 -110
- package/dist/shell/panel-windows.d.ts +2 -0
- package/dist/shell/panel-windows.js +7 -2
- package/dist/shell/panel-windows.js.map +2 -2
- package/dist/studio/index.cjs +28 -26
- package/dist/studio/index.cjs.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +55 -54
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +6 -5
- package/dist/ConnectedCallDock-WER7R222.cjs.map +0 -1
- package/dist/DocumentReviewCard-BPIAJJED.cjs.map +0 -1
- package/dist/FilesViewerDialog-67WK3TZC.cjs.map +0 -1
- package/dist/GridViewImpl-ZMJJWTOM.cjs.map +0 -1
- package/dist/WorkspaceTableView-J3C6VH4T.cjs.map +0 -1
- package/dist/ai-IM4A23YT.cjs.map +0 -1
- package/dist/chunk-557MJ4IH.cjs.map +0 -1
- package/dist/chunk-6UTKM5AB.cjs.map +0 -1
- package/dist/chunk-6WMMZLEV.cjs.map +0 -1
- package/dist/chunk-B3LZITVF.cjs.map +0 -1
- package/dist/chunk-BUVIBHFU.cjs.map +0 -1
- package/dist/chunk-CPR6EHG7.cjs.map +0 -1
- package/dist/chunk-HA66DHW6.cjs.map +0 -1
- package/dist/chunk-NJCK6V6U.cjs.map +0 -1
- package/dist/chunk-NLSWDP42.cjs.map +0 -1
- package/dist/chunk-PGJYD67F.cjs.map +0 -1
- package/dist/chunk-X36UR4A7.cjs.map +0 -1
- package/dist/chunk-YYPZOEED.cjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/connection/files/explorer/FileTiles.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * The explorer's one tile binding. The presentation (`ExplorerFileTile`, `ExplorerFolderTile`,\n * `ExplorerFileTooltip`) is in `files/`; this binds it to the session: @dnd-kit draggable and\n * droppable, the document's live processing status, the copies kept offline, the open viewer, the\n * document pill, the mail handoff and the member / label lookups. `FileTile` is a draggable\n * document, `FolderTile` a droppable folder (separate components so the dnd hooks always run).\n */\n\nimport { memo, useMemo, type ReactNode } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport {\n AlertTriangle,\n BookOpen,\n CheckCircle,\n Download,\n FileX,\n FolderInput,\n Mail,\n MessagesSquare,\n Pencil,\n Play,\n SkipForward,\n Sparkles,\n SquarePen,\n Trash2,\n} from 'lucide-react'\nimport {\n FINISHED_DOCUMENT_STATUSES,\n IN_FLIGHT_DOCUMENT_STATUSES,\n resolveDocumentStatus,\n useMailPolicy,\n useOfflineDocumentIds,\n useOpenViewerDocumentId,\n useProcessingTask,\n useProcessingTasks,\n type DocumentHostActions,\n type DocumentStartItem,\n type WorkspaceDocument,\n} from '@arbidocs/react'\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n DocumentEntity,\n VisibilityIcon,\n cn,\n formatFriendlyDate,\n getEntityLabel,\n getDocumentTitle,\n getFileTypeIcon,\n getUserAvatarColor,\n getUserDisplayName,\n getUserInitials,\n getDocumentSubject,\n} from '@arbidocs/react/ui'\nimport {\n ExplorerFileTile,\n ExplorerFileTooltip,\n ExplorerFolderTile,\n type ExplorerDensity,\n type ExplorerMenuItem,\n} from '../../../files/ExplorerTile'\nimport { StatusPill, type StatusTone } from '../../../files/StatusPill'\nimport { FailedStageIcon } from '../../../files/FailedStageIcon'\nimport { visibilityAudience } from '../../../files/visibility'\nimport {\n FolderProviderIcon,\n formatFolderSegment,\n hasFolderProviderIcon,\n type ExplorerFolder,\n} from '../../../files/folders'\nimport { useBlocksEnvironment } from '../../../provider/environment'\nimport { DocumentSyncGlyph } from '../DocumentSyncGlyph'\n\nexport type { ExplorerDensity }\n\n/** A workspace member as a tile shows them (avatar and name). */\nexport interface FileTileUser {\n external_id: string\n given_name: string\n family_name?: string | null\n email: string\n picture?: string | null\n}\n\n/** A document row as the tiles read it (the session's rows carry these). */\nexport type FileTileDocument = WorkspaceDocument & {\n failed_stage?: string | null\n}\n\nconst NO_ACTIONS: DocumentHostActions = {}\n\n// In-flight processing statuses (the table's status cell has the same) and the terminal ones.\nconst ACTIVE_STATUSES = IN_FLIGHT_DOCUMENT_STATUSES\nconst TERMINAL_STATUSES = FINISHED_DOCUMENT_STATUSES\nconst STATUS_LABEL: Record<string, string> = {\n uploading: 'Uploading',\n queued: 'Queued',\n parsing: 'Parsing',\n encrypting: 'Encrypting',\n indexing: 'Indexing',\n analysing: 'Analysing',\n}\n\n/** Whether a status is still being worked on. */\nexport function isActiveDocumentStatus(status: string): boolean {\n return ACTIVE_STATUSES.has(status.toLowerCase())\n}\n\n/**\n * The document's effective status: the newer of its row and its live processing\n * (`resolveDocumentStatus`). Reads only this document's live processing, so a tile re-renders only\n * when its own status changes.\n */\nfunction useDocStatus(doc: FileTileDocument): string {\n return resolveDocumentStatus(doc, useProcessingTask(doc.external_id))\n}\n\n/** The finished-state marker in the tile's lower-right corner (in-flight files use the overlay). */\nfunction TileStatusBadge({ doc, status }: { doc: FileTileDocument; status: string }): ReactNode {\n let tone: StatusTone = 'neutral'\n let icon: ReactNode = null\n let title = ''\n switch (status) {\n case 'completed':\n tone = 'success'\n icon = <CheckCircle className=\"size-4 text-green-text\" strokeWidth={2.75} />\n title = 'Ready'\n break\n case 'failed':\n tone = 'danger'\n icon = (\n <FailedStageIcon\n stage={doc.failed_stage ?? null}\n errorMessage={doc.error_message}\n className=\"size-4 text-red-text\"\n />\n )\n title = 'Failed'\n break\n case 'skipped':\n icon = <SkipForward className=\"size-4 text-muted-foreground\" strokeWidth={2.75} />\n title = 'Skipped'\n break\n case 'empty':\n tone = 'warning'\n icon = <FileX className=\"size-4 text-yellow-text\" strokeWidth={2.75} />\n title = 'Empty \u2014 no extractable content'\n break\n case 'low-content':\n tone = 'warning'\n icon = <AlertTriangle className=\"size-4 text-yellow-text\" strokeWidth={2.75} />\n title = 'Low content \u2014 minimal extractable content'\n break\n default:\n return null\n }\n return (\n <StatusPill\n tone={tone}\n icon={icon}\n title={title}\n testId={`explorer-file-status-${doc.external_id}`}\n />\n )\n}\n\n/**\n * Who can see the file, printed on the tile itself: a bare \"Shared\" does not say with whom, and a\n * hover title never reaches touch and keyboard users. The label is the audience's short name so it\n * fits beside the status check on narrow tiles; the title keeps the full sentence.\n */\nfunction TileVisibilityBadge({ doc }: { doc: FileTileDocument }): ReactNode {\n const shared = !!doc.shared\n return (\n <StatusPill\n icon={<VisibilityIcon isShared={shared} className=\"size-3.5\" aria-hidden />}\n label={shared ? getEntityLabel('WORKSPACE') : 'Only you'}\n title={visibilityAudience(shared)}\n testId={`explorer-file-visibility-${doc.external_id}`}\n />\n )\n}\n\n/** A tiny avatar (initials, or the picture when set) for the \"last modified by\" line. */\nfunction MiniUserAvatar({ user }: { user: FileTileUser }) {\n return (\n <Avatar className=\"h-4 w-4 border border-white\">\n {user.picture && <AvatarImage src={user.picture} alt={getUserDisplayName(user)} />}\n <AvatarFallback\n className={cn(\n 'text-xs font-semibold leading-none text-white',\n getUserAvatarColor(user.external_id)\n )}\n >\n {getUserInitials(user)}\n </AvatarFallback>\n </Avatar>\n )\n}\n\n/** The hover card of a document: the same in the explorer tiles and the table's name cell. */\nexport function FileTooltipContent({\n doc,\n modifiedBy,\n tagNameById,\n}: {\n doc: FileTileDocument\n modifiedBy?: FileTileUser\n tagNameById: ReadonlyMap<string, string>\n}) {\n const labels = (doc.doctags ?? [])\n .map((dt) => tagNameById.get(dt.tag_ext_id))\n .filter((name): name is string => !!name)\n return (\n <ExplorerFileTooltip\n title={getDocumentTitle(doc, doc.file_name ?? '')}\n summary={getDocumentSubject(doc)}\n modifiedLabel={doc.updated_at ? formatFriendlyDate(doc.updated_at, false) : null}\n modifiedByAvatar={modifiedBy && <MiniUserAvatar user={modifiedBy} />}\n shared={!!doc.shared}\n visibilityIcon={<VisibilityIcon isShared={!!doc.shared} className=\"h-3 w-3\" />}\n labels={labels}\n uiLabels={{ shared: visibilityAudience(true), private: visibilityAudience(false) }}\n />\n )\n}\n\n/** The \"Start\u2026\" submenu: one entry per thing the host can start on the file or folder. */\nexport function startMenuItem(items: readonly DocumentStartItem[]): ExplorerMenuItem[] {\n if (items.length === 0) return []\n return [\n {\n id: 'start',\n label: 'Start\u2026',\n icon: Sparkles,\n testId: 'explorer-start-menu',\n onSelect: () => {},\n submenu: items.map((item) => ({\n id: item.id,\n label: item.title,\n icon: Play,\n onSelect: item.run,\n testId: `explorer-start-${item.id}`,\n })),\n },\n ]\n}\n\ninterface FileTileProps {\n doc: FileTileDocument\n density: ExplorerDensity\n selected: boolean\n /** Part of an in-flight drag (dimmed). */\n dragging: boolean\n /** Any tile is being dragged: no hover card, so it cannot swallow the moves dnd-kit tracks. */\n dndActive: boolean\n /** Being renamed inline. */\n renaming: boolean\n /** The viewer may delete this document. */\n canDelete: boolean\n /** The first-page thumbnail (absent: the file-type icon). */\n thumbnailUrl?: string\n /** Who last changed the document (the hover card's avatar line). */\n modifiedBy?: FileTileUser\n /** Label id \u2192 name, for the document's labels on the hover card. */\n tagNameById: ReadonlyMap<string, string>\n onSelect: (doc: FileTileDocument, e: React.MouseEvent) => void\n onToggle: (doc: FileTileDocument, e: React.MouseEvent) => void\n onOpen: (doc: FileTileDocument) => void\n /** Open the document in the review view. Absent: not offered. */\n onReview?: (doc: FileTileDocument) => void\n onStartRename: (doc: FileTileDocument) => void\n onCommitRename: (doc: FileTileDocument, name: string) => void\n onCancelRename: () => void\n onDownload: (doc: FileTileDocument) => void\n onMove?: (doc: FileTileDocument) => void\n onDelete: (doc: FileTileDocument) => void\n /** The host's actions on documents (read once by the view). */\n actions?: DocumentHostActions\n}\n\nexport const FileTile = memo(function FileTile({\n doc,\n density,\n selected,\n dragging,\n dndActive,\n renaming,\n canDelete,\n thumbnailUrl,\n modifiedBy,\n tagNameById,\n onSelect,\n onToggle,\n onOpen,\n onReview,\n onStartRename,\n onCommitRename,\n onCancelRename,\n onDownload,\n onMove,\n onDelete,\n actions = NO_ACTIONS,\n}: FileTileProps) {\n const { attributes, listeners, setNodeRef } = useDraggable({\n id: `doc:${doc.external_id}`,\n data: { type: 'doc', docId: doc.external_id },\n })\n const { notify } = useBlocksEnvironment()\n const { startItemsForFile, openDocumentChat, emailDocument } = actions\n const status = useDocStatus(doc)\n const isProcessing = ACTIVE_STATUSES.has(status)\n const isOffline = useOfflineDocumentIds().has(doc.external_id)\n const isViewing = useOpenViewerDocumentId() === doc.external_id\n const showStatusMarker = !isProcessing && TERMINAL_STATUSES.has(status)\n const Icon = getFileTypeIcon(doc.file_name, { mime: doc.file_type })\n const { data: mailPolicy } = useMailPolicy()\n\n const shareAsEmail = async () => {\n try {\n await emailDocument?.(doc)\n } catch (error) {\n notify(error instanceof Error ? error.message : 'Could not attach document', 'error')\n }\n }\n const startItems = startItemsForFile?.(doc)\n const menuItems: ExplorerMenuItem[] = [\n { id: 'open', label: 'Open', icon: SquarePen, onSelect: () => onOpen(doc) },\n ...(onReview\n ? [{ id: 'review', label: 'Open in Review', icon: BookOpen, onSelect: () => onReview(doc) }]\n : []),\n ...(openDocumentChat\n ? [\n {\n id: 'chat',\n label: 'Document chat',\n icon: MessagesSquare,\n onSelect: () => openDocumentChat(doc.external_id),\n },\n ]\n : []),\n ...startMenuItem(startItems ?? []),\n {\n id: 'rename',\n label: 'Rename',\n icon: Pencil,\n onSelect: () => onStartRename(doc),\n separatorBefore: true,\n },\n { id: 'download', label: 'Download', icon: Download, onSelect: () => onDownload(doc) },\n ...(emailDocument && mailPolicy?.enabled\n ? [\n {\n id: 'email',\n label: 'Send as email attachment',\n icon: Mail,\n onSelect: () => {\n void shareAsEmail()\n },\n },\n ]\n : []),\n ...(onMove\n ? [{ id: 'move', label: 'Move to\u2026', icon: FolderInput, onSelect: () => onMove(doc) }]\n : []),\n ...(canDelete\n ? [\n {\n id: 'delete',\n label: 'Delete',\n icon: Trash2,\n onSelect: () => onDelete(doc),\n destructive: true,\n separatorBefore: true,\n },\n ]\n : []),\n ]\n\n // No hover card while renaming (it would cover the input) or while anything is dragged: the\n // tooltip trigger merges pointer handlers onto the draggable node and swallows the move events\n // dnd-kit needs to find the drop target.\n const tooltip =\n renaming || dndActive ? undefined : (\n <FileTooltipContent doc={doc} modifiedBy={modifiedBy} tagNameById={tagNameById} />\n )\n\n return (\n <ExplorerFileTile\n id={doc.external_id}\n title={getDocumentTitle(doc, doc.file_name ?? '')}\n density={density}\n selected={selected}\n dragging={dragging}\n renaming={renaming}\n thumbnailUrl={thumbnailUrl}\n renderFileIcon={(size) => <Icon size={size} className=\"drop-shadow-sm\" />}\n progress={\n isProcessing\n ? { label: STATUS_LABEL[status] ?? status, queued: status === 'queued' }\n : undefined\n }\n statusMarker={\n <div className=\"flex items-center gap-1\">\n <TileVisibilityBadge doc={doc} />\n {showStatusMarker && <TileStatusBadge doc={doc} status={status} />}\n </div>\n }\n offlineMarker={\n isOffline ? (\n <DocumentSyncGlyph docExtId={doc.external_id} size={24} bgClassName=\"bg-primary\" />\n ) : undefined\n }\n entity={\n <DocumentEntity\n doc={doc}\n labelMaxWidth=\"max-w-full\"\n noClamp\n // The full name over two lines: \"(redacted)\" / \"(annotated)\" sit at the end, so a one-line\n // ellipsis hides exactly what tells a frozen copy from its original.\n labelClassName=\"whitespace-normal line-clamp-2 break-words\"\n viewing={isViewing}\n tooltipContent={\n <FileTooltipContent doc={doc} modifiedBy={modifiedBy} tagNameById={tagNameById} />\n }\n className={cn(\n 'w-full min-w-0 max-w-full bg-background/90 backdrop-blur-sm',\n density === 'list' ? 'text-xs' : undefined\n )}\n onClick={(e) => {\n e.stopPropagation()\n onOpen(doc)\n }}\n />\n }\n tooltip={tooltip}\n menuItems={menuItems}\n rootRef={setNodeRef}\n rootProps={{ ...listeners, ...attributes }}\n onOpen={() => onOpen(doc)}\n onSelect={(e) => onSelect(doc, e)}\n onToggle={(e) => onToggle(doc, e)}\n onCommitRename={(name) => onCommitRename(doc, name)}\n onCancelRename={onCancelRename}\n />\n )\n})\n\ninterface FolderTileProps {\n folder: ExplorerFolder\n density: ExplorerDensity\n /** Being renamed inline. */\n editing?: boolean\n /** Every document beneath the folder is selected. */\n selected?: boolean\n /** Some (not all) documents beneath the folder are selected. */\n partiallySelected?: boolean\n /** Every document beneath the folder (its count of files still processing). */\n documents: readonly FileTileDocument[]\n onOpen: (folder: ExplorerFolder) => void\n /** Toggle the whole folder (all its documents). */\n onToggleSelect?: (folder: ExplorerFolder, e: React.MouseEvent) => void\n onCommitName?: (folder: ExplorerFolder, name: string) => void\n onCancelName?: () => void\n onStartRename?: (folder: ExplorerFolder) => void\n onDownload?: (folder: ExplorerFolder) => void\n onMove?: (folder: ExplorerFolder) => void\n onDelete?: (folder: ExplorerFolder) => void\n /** The host's actions on documents (read once by the view). */\n actions?: DocumentHostActions\n}\n\nexport const FolderTile = memo(function FolderTile({\n folder,\n density,\n editing,\n selected,\n partiallySelected,\n documents,\n onOpen,\n onToggleSelect,\n onCommitName,\n onCancelName,\n onStartRename,\n onDownload,\n onMove,\n onDelete,\n actions = NO_ACTIONS,\n}: FolderTileProps) {\n const { setNodeRef, isOver } = useDroppable({\n id: `folder:${folder.path.join('/')}`,\n data: { type: 'folder', path: folder.path },\n })\n const { startItemsForFolder } = actions\n // Live processing is read here, not by the explorer, so an upload burst re-renders folder tiles\n // only.\n const tasks = useProcessingTasks()\n const processingCount = useMemo(\n () =>\n documents.filter((doc) =>\n isActiveDocumentStatus(resolveDocumentStatus(doc, tasks[doc.external_id]))\n ).length,\n [documents, tasks]\n )\n const isEmpty = folder.count === 0\n const iconSize = density === 'list' ? 34 : 48\n\n // A folder is not \"opened in review\"; an item is left out when its handler is absent (an empty\n // folder has nothing to start, download or move).\n const menuItems: ExplorerMenuItem[] = [\n ...(onStartRename\n ? [{ id: 'rename', label: 'Rename', icon: Pencil, onSelect: () => onStartRename(folder) }]\n : []),\n ...(!isEmpty ? startMenuItem(startItemsForFolder?.(folder.path.join('/')) ?? []) : []),\n ...(onDownload && !isEmpty\n ? [{ id: 'download', label: 'Download', icon: Download, onSelect: () => onDownload(folder) }]\n : []),\n ...(onMove && !isEmpty\n ? [{ id: 'move', label: 'Move to\u2026', icon: FolderInput, onSelect: () => onMove(folder) }]\n : []),\n ...(onDelete\n ? [\n {\n id: 'delete',\n label: 'Delete',\n icon: Trash2,\n onSelect: () => onDelete(folder),\n destructive: true,\n separatorBefore: true,\n },\n ]\n : []),\n ]\n\n // A provider root shows shortened (the account; the brand mark carries the provider). Rename and\n // the tooltip keep the full stored name.\n const displayName = folder.path.length === 1 ? formatFolderSegment(folder.name) : folder.name\n const providerIcon =\n folder.path.length === 1 && hasFolderProviderIcon(folder.name) ? (\n <span\n className=\"flex items-center justify-center drop-shadow-sm\"\n style={{ width: iconSize, height: iconSize }}\n >\n <FolderProviderIcon folderPath={folder.name} className=\"h-full w-full\" />\n </span>\n ) : undefined\n\n return (\n <ExplorerFolderTile\n name={folder.name}\n displayName={displayName === '' ? null : displayName}\n path={folder.path}\n count={folder.count}\n density={density}\n editing={editing}\n selected={selected}\n partiallySelected={partiallySelected}\n processingCount={processingCount}\n isOver={isOver}\n icon={providerIcon}\n menuItems={menuItems}\n rootRef={setNodeRef}\n onOpen={() => onOpen(folder)}\n onToggleSelect={onToggleSelect ? (e) => onToggleSelect(folder, e) : undefined}\n onCommitName={(name) => onCommitName?.(folder, name)}\n onCancelName={onCancelName}\n />\n )\n})\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["/**\n * The explorer's one tile binding. The presentation (`ExplorerFileTile`, `ExplorerFolderTile`,\n * `ExplorerFileTooltip`) is in `files/`; this binds it to the session: @dnd-kit draggable and\n * droppable, the document's live processing status, the copies kept offline, the open viewer, the\n * document pill, the mail handoff and the member / label lookups. `FileTile` is a draggable\n * document, `FolderTile` a droppable folder (separate components so the dnd hooks always run).\n */\n\nimport { memo, useMemo, type ReactNode } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport {\n AlertTriangle,\n BookOpen,\n CheckCircle,\n Download,\n FileX,\n FolderInput,\n Mail,\n MessagesSquare,\n Pencil,\n Play,\n SkipForward,\n Sparkles,\n SquarePen,\n Trash2,\n} from 'lucide-react'\nimport {\n FINISHED_DOCUMENT_STATUSES,\n IN_FLIGHT_DOCUMENT_STATUSES,\n resolveDocumentStatus,\n useMailPolicy,\n useOfflineDocumentIds,\n useOpenViewerDocumentId,\n useProcessingTask,\n useProcessingTasks,\n type DocumentHostActions,\n type DocumentStartItem,\n type WorkspaceDocument,\n} from '@arbidocs/react'\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n DocumentEntity,\n VisibilityIcon,\n cn,\n formatFriendlyDate,\n getEntityLabel,\n getDocumentTitle,\n getFileTypeIcon,\n getUserAvatarColor,\n getUserDisplayName,\n getUserInitials,\n getDocumentSubject,\n} from '@arbidocs/react/ui'\nimport {\n ExplorerFileTile,\n ExplorerFileTooltip,\n ExplorerFolderTile,\n type ExplorerDensity,\n type ExplorerMenuItem,\n} from '../../../files/ExplorerTile'\nimport { StatusPill, type StatusTone } from '../../../files/StatusPill'\nimport { FailedStageIcon } from '../../../files/FailedStageIcon'\nimport { visibilityAudience } from '../../../files/visibility'\nimport {\n FolderProviderIcon,\n formatFolderSegment,\n hasFolderProviderIcon,\n type ExplorerFolder,\n} from '../../../files/folders'\nimport { useBlocksEnvironment } from '../../../provider/environment'\nimport { DocumentSyncGlyph } from '../DocumentSyncGlyph'\n\nexport type { ExplorerDensity }\n\n/** A workspace member as a tile shows them (avatar and name). */\nexport interface FileTileUser {\n external_id: string\n given_name: string\n family_name?: string | null\n email: string\n picture?: string | null\n}\n\n/** A document row as the tiles read it (the session's rows carry these). */\nexport type FileTileDocument = WorkspaceDocument & {\n failed_stage?: string | null\n}\n\nconst NO_ACTIONS: DocumentHostActions = {}\n\n// In-flight processing statuses (the table's status cell has the same) and the terminal ones.\nconst ACTIVE_STATUSES = IN_FLIGHT_DOCUMENT_STATUSES\nconst TERMINAL_STATUSES = FINISHED_DOCUMENT_STATUSES\nconst STATUS_LABEL: Record<string, string> = {\n uploading: 'Uploading',\n queued: 'Queued',\n parsing: 'Parsing',\n encrypting: 'Encrypting',\n indexing: 'Indexing',\n analysing: 'Analysing',\n}\n\n/** Whether a status is still being worked on. */\nexport function isActiveDocumentStatus(status: string): boolean {\n return ACTIVE_STATUSES.has(status.toLowerCase())\n}\n\n/**\n * The document's effective status: the newer of its row and its live processing\n * (`resolveDocumentStatus`). Reads only this document's live processing, so a tile re-renders only\n * when its own status changes.\n */\nfunction useDocStatus(doc: FileTileDocument): string {\n return resolveDocumentStatus(doc, useProcessingTask(doc.external_id))\n}\n\n/** The finished-state marker in the tile's lower-right corner (in-flight files use the overlay). */\nfunction TileStatusBadge({ doc, status }: { doc: FileTileDocument; status: string }): ReactNode {\n let tone: StatusTone = 'neutral'\n let icon: ReactNode = null\n let title = ''\n switch (status) {\n case 'completed':\n tone = 'success'\n icon = <CheckCircle className=\"size-4 text-green-text\" strokeWidth={2.75} />\n title = 'Ready'\n break\n case 'failed':\n tone = 'danger'\n icon = (\n <FailedStageIcon\n stage={doc.failed_stage ?? null}\n errorMessage={doc.error_message}\n className=\"size-4 text-red-text\"\n />\n )\n title = 'Failed'\n break\n case 'skipped':\n icon = <SkipForward className=\"size-4 text-muted-foreground\" strokeWidth={2.75} />\n title = 'Skipped'\n break\n case 'empty':\n tone = 'warning'\n icon = <FileX className=\"size-4 text-yellow-text\" strokeWidth={2.75} />\n title = 'Empty \u2014 no extractable content'\n break\n case 'low-content':\n tone = 'warning'\n icon = <AlertTriangle className=\"size-4 text-yellow-text\" strokeWidth={2.75} />\n title = 'Low content \u2014 minimal extractable content'\n break\n default:\n return null\n }\n return (\n <StatusPill\n tone={tone}\n icon={icon}\n title={title}\n testId={`explorer-file-status-${doc.external_id}`}\n />\n )\n}\n\n/**\n * Who can see the file, printed on the tile itself: a bare \"Shared\" does not say with whom, and a\n * hover title never reaches touch and keyboard users. The label is the audience's short name so it\n * fits beside the status check on narrow tiles; the title keeps the full sentence.\n */\nfunction TileVisibilityBadge({ doc }: { doc: FileTileDocument }): ReactNode {\n const shared = !!doc.shared\n return (\n <StatusPill\n icon={<VisibilityIcon isShared={shared} className=\"size-3.5\" aria-hidden />}\n label={shared ? getEntityLabel('WORKSPACE') : 'Only you'}\n title={visibilityAudience(shared)}\n testId={`explorer-file-visibility-${doc.external_id}`}\n />\n )\n}\n\n/** A tiny avatar (initials, or the picture when set) for the \"last modified by\" line. */\nfunction MiniUserAvatar({ user }: { user: FileTileUser }) {\n return (\n <Avatar className=\"h-4 w-4 border border-white\">\n {user.picture && <AvatarImage src={user.picture} alt={getUserDisplayName(user)} />}\n <AvatarFallback\n className={cn(\n 'text-xs font-semibold leading-none text-white',\n getUserAvatarColor(user.external_id)\n )}\n >\n {getUserInitials(user)}\n </AvatarFallback>\n </Avatar>\n )\n}\n\n/** The hover card of a document: the same in the explorer tiles and the table's name cell. */\nexport function FileTooltipContent({\n doc,\n modifiedBy,\n tagNameById,\n}: {\n doc: FileTileDocument\n modifiedBy?: FileTileUser\n tagNameById: ReadonlyMap<string, string>\n}) {\n const labels = (doc.doctags ?? [])\n .map((dt) => tagNameById.get(dt.tag_ext_id))\n .filter((name): name is string => !!name)\n return (\n <ExplorerFileTooltip\n title={getDocumentTitle(doc, doc.file_name ?? '')}\n summary={getDocumentSubject(doc)}\n modifiedLabel={doc.updated_at ? formatFriendlyDate(doc.updated_at, false) : null}\n modifiedByAvatar={modifiedBy && <MiniUserAvatar user={modifiedBy} />}\n shared={!!doc.shared}\n visibilityIcon={<VisibilityIcon isShared={!!doc.shared} className=\"h-3 w-3\" />}\n labels={labels}\n uiLabels={{ shared: visibilityAudience(true), private: visibilityAudience(false) }}\n />\n )\n}\n\n/** The \"Start\u2026\" submenu: one entry per thing the host can start on the file or folder. */\nexport function startMenuItem(items: readonly DocumentStartItem[]): ExplorerMenuItem[] {\n if (items.length === 0) return []\n return [\n {\n id: 'start',\n label: 'Start\u2026',\n icon: Sparkles,\n testId: 'explorer-start-menu',\n onSelect: () => {},\n submenu: items.map((item) => ({\n id: item.id,\n label: item.title,\n icon: Play,\n onSelect: item.run,\n testId: `explorer-start-${item.id}`,\n })),\n },\n ]\n}\n\ninterface FileTileProps {\n doc: FileTileDocument\n density: ExplorerDensity\n selected: boolean\n /** Part of an in-flight drag (dimmed). */\n dragging: boolean\n /** Any tile is being dragged: no hover card, so it cannot swallow the moves dnd-kit tracks. */\n dndActive: boolean\n /** Being renamed inline. */\n renaming: boolean\n /** The viewer may delete this document. */\n canDelete: boolean\n /** The first-page thumbnail (absent: the file-type icon). */\n thumbnailUrl?: string\n /** Who last changed the document (the hover card's avatar line). */\n modifiedBy?: FileTileUser\n /** Label id \u2192 name, for the document's labels on the hover card. */\n tagNameById: ReadonlyMap<string, string>\n onSelect: (doc: FileTileDocument, e: React.MouseEvent) => void\n onToggle: (doc: FileTileDocument, e: React.MouseEvent) => void\n onOpen: (doc: FileTileDocument) => void\n /** Open the document in the review view. Absent: not offered. */\n onReview?: (doc: FileTileDocument) => void\n onStartRename: (doc: FileTileDocument) => void\n onCommitRename: (doc: FileTileDocument, name: string) => void\n onCancelRename: () => void\n onDownload: (doc: FileTileDocument) => void\n onMove?: (doc: FileTileDocument) => void\n onDelete: (doc: FileTileDocument) => void\n /** The host's actions on documents (read once by the view). */\n actions?: DocumentHostActions\n}\n\nexport const FileTile = memo(function FileTile({\n doc,\n density,\n selected,\n dragging,\n dndActive,\n renaming,\n canDelete,\n thumbnailUrl,\n modifiedBy,\n tagNameById,\n onSelect,\n onToggle,\n onOpen,\n onReview,\n onStartRename,\n onCommitRename,\n onCancelRename,\n onDownload,\n onMove,\n onDelete,\n actions = NO_ACTIONS,\n}: FileTileProps) {\n const { attributes, listeners, setNodeRef } = useDraggable({\n id: `doc:${doc.external_id}`,\n data: { type: 'doc', docId: doc.external_id },\n })\n const { notify } = useBlocksEnvironment()\n const { startItemsForFile, openDocumentChat, emailDocument } = actions\n const status = useDocStatus(doc)\n const isProcessing = ACTIVE_STATUSES.has(status)\n const isOffline = useOfflineDocumentIds().has(doc.external_id)\n const isViewing = useOpenViewerDocumentId() === doc.external_id\n const showStatusMarker = !isProcessing && TERMINAL_STATUSES.has(status)\n const Icon = getFileTypeIcon(doc.file_name, { mime: doc.file_type, folder: doc.folder })\n const { data: mailPolicy } = useMailPolicy()\n\n const shareAsEmail = async () => {\n try {\n await emailDocument?.(doc)\n } catch (error) {\n notify(error instanceof Error ? error.message : 'Could not attach document', 'error')\n }\n }\n const startItems = startItemsForFile?.(doc)\n const menuItems: ExplorerMenuItem[] = [\n { id: 'open', label: 'Open', icon: SquarePen, onSelect: () => onOpen(doc) },\n ...(onReview\n ? [{ id: 'review', label: 'Open in Review', icon: BookOpen, onSelect: () => onReview(doc) }]\n : []),\n ...(openDocumentChat\n ? [\n {\n id: 'chat',\n label: 'Document chat',\n icon: MessagesSquare,\n onSelect: () => openDocumentChat(doc.external_id),\n },\n ]\n : []),\n ...startMenuItem(startItems ?? []),\n {\n id: 'rename',\n label: 'Rename',\n icon: Pencil,\n onSelect: () => onStartRename(doc),\n separatorBefore: true,\n },\n { id: 'download', label: 'Download', icon: Download, onSelect: () => onDownload(doc) },\n ...(emailDocument && mailPolicy?.enabled\n ? [\n {\n id: 'email',\n label: 'Send as email attachment',\n icon: Mail,\n onSelect: () => {\n void shareAsEmail()\n },\n },\n ]\n : []),\n ...(onMove\n ? [{ id: 'move', label: 'Move to\u2026', icon: FolderInput, onSelect: () => onMove(doc) }]\n : []),\n ...(canDelete\n ? [\n {\n id: 'delete',\n label: 'Delete',\n icon: Trash2,\n onSelect: () => onDelete(doc),\n destructive: true,\n separatorBefore: true,\n },\n ]\n : []),\n ]\n\n // No hover card while renaming (it would cover the input) or while anything is dragged: the\n // tooltip trigger merges pointer handlers onto the draggable node and swallows the move events\n // dnd-kit needs to find the drop target.\n const tooltip =\n renaming || dndActive ? undefined : (\n <FileTooltipContent doc={doc} modifiedBy={modifiedBy} tagNameById={tagNameById} />\n )\n\n return (\n <ExplorerFileTile\n id={doc.external_id}\n title={getDocumentTitle(doc, doc.file_name ?? '')}\n density={density}\n selected={selected}\n dragging={dragging}\n renaming={renaming}\n thumbnailUrl={thumbnailUrl}\n renderFileIcon={(size) => <Icon size={size} className=\"drop-shadow-sm\" />}\n progress={\n isProcessing\n ? { label: STATUS_LABEL[status] ?? status, queued: status === 'queued' }\n : undefined\n }\n statusMarker={\n <div className=\"flex items-center gap-1\">\n <TileVisibilityBadge doc={doc} />\n {showStatusMarker && <TileStatusBadge doc={doc} status={status} />}\n </div>\n }\n offlineMarker={\n isOffline ? (\n <DocumentSyncGlyph docExtId={doc.external_id} size={24} bgClassName=\"bg-primary\" />\n ) : undefined\n }\n entity={\n <DocumentEntity\n doc={doc}\n labelMaxWidth=\"max-w-full\"\n noClamp\n // The full name over two lines: \"(redacted)\" / \"(annotated)\" sit at the end, so a one-line\n // ellipsis hides exactly what tells a frozen copy from its original.\n labelClassName=\"whitespace-normal line-clamp-2 break-words\"\n viewing={isViewing}\n tooltipContent={\n <FileTooltipContent doc={doc} modifiedBy={modifiedBy} tagNameById={tagNameById} />\n }\n className={cn(\n 'w-full min-w-0 max-w-full bg-background/90 backdrop-blur-sm',\n density === 'list' ? 'text-xs' : undefined\n )}\n onClick={(e) => {\n e.stopPropagation()\n onOpen(doc)\n }}\n />\n }\n tooltip={tooltip}\n menuItems={menuItems}\n rootRef={setNodeRef}\n rootProps={{ ...listeners, ...attributes }}\n onOpen={() => onOpen(doc)}\n onSelect={(e) => onSelect(doc, e)}\n onToggle={(e) => onToggle(doc, e)}\n onCommitRename={(name) => onCommitRename(doc, name)}\n onCancelRename={onCancelRename}\n />\n )\n})\n\ninterface FolderTileProps {\n folder: ExplorerFolder\n density: ExplorerDensity\n /** Being renamed inline. */\n editing?: boolean\n /** Every document beneath the folder is selected. */\n selected?: boolean\n /** Some (not all) documents beneath the folder are selected. */\n partiallySelected?: boolean\n /** Every document beneath the folder (its count of files still processing). */\n documents: readonly FileTileDocument[]\n onOpen: (folder: ExplorerFolder) => void\n /** Toggle the whole folder (all its documents). */\n onToggleSelect?: (folder: ExplorerFolder, e: React.MouseEvent) => void\n onCommitName?: (folder: ExplorerFolder, name: string) => void\n onCancelName?: () => void\n onStartRename?: (folder: ExplorerFolder) => void\n onDownload?: (folder: ExplorerFolder) => void\n onMove?: (folder: ExplorerFolder) => void\n onDelete?: (folder: ExplorerFolder) => void\n /** The host's actions on documents (read once by the view). */\n actions?: DocumentHostActions\n}\n\nexport const FolderTile = memo(function FolderTile({\n folder,\n density,\n editing,\n selected,\n partiallySelected,\n documents,\n onOpen,\n onToggleSelect,\n onCommitName,\n onCancelName,\n onStartRename,\n onDownload,\n onMove,\n onDelete,\n actions = NO_ACTIONS,\n}: FolderTileProps) {\n const { setNodeRef, isOver } = useDroppable({\n id: `folder:${folder.path.join('/')}`,\n data: { type: 'folder', path: folder.path },\n })\n const { startItemsForFolder } = actions\n // Live processing is read here, not by the explorer, so an upload burst re-renders folder tiles\n // only.\n const tasks = useProcessingTasks()\n const processingCount = useMemo(\n () =>\n documents.filter((doc) =>\n isActiveDocumentStatus(resolveDocumentStatus(doc, tasks[doc.external_id]))\n ).length,\n [documents, tasks]\n )\n const isEmpty = folder.count === 0\n const iconSize = density === 'list' ? 34 : 48\n\n // A folder is not \"opened in review\"; an item is left out when its handler is absent (an empty\n // folder has nothing to start, download or move).\n const menuItems: ExplorerMenuItem[] = [\n ...(onStartRename\n ? [{ id: 'rename', label: 'Rename', icon: Pencil, onSelect: () => onStartRename(folder) }]\n : []),\n ...(!isEmpty ? startMenuItem(startItemsForFolder?.(folder.path.join('/')) ?? []) : []),\n ...(onDownload && !isEmpty\n ? [{ id: 'download', label: 'Download', icon: Download, onSelect: () => onDownload(folder) }]\n : []),\n ...(onMove && !isEmpty\n ? [{ id: 'move', label: 'Move to\u2026', icon: FolderInput, onSelect: () => onMove(folder) }]\n : []),\n ...(onDelete\n ? [\n {\n id: 'delete',\n label: 'Delete',\n icon: Trash2,\n onSelect: () => onDelete(folder),\n destructive: true,\n separatorBefore: true,\n },\n ]\n : []),\n ]\n\n // A provider root shows shortened (the account; the brand mark carries the provider). Rename and\n // the tooltip keep the full stored name.\n const displayName = folder.path.length === 1 ? formatFolderSegment(folder.name) : folder.name\n const providerIcon =\n folder.path.length === 1 && hasFolderProviderIcon(folder.name) ? (\n <span\n className=\"flex items-center justify-center drop-shadow-sm\"\n style={{ width: iconSize, height: iconSize }}\n >\n <FolderProviderIcon folderPath={folder.name} className=\"h-full w-full\" />\n </span>\n ) : undefined\n\n return (\n <ExplorerFolderTile\n name={folder.name}\n displayName={displayName === '' ? null : displayName}\n path={folder.path}\n count={folder.count}\n density={density}\n editing={editing}\n selected={selected}\n partiallySelected={partiallySelected}\n processingCount={processingCount}\n isOver={isOver}\n icon={providerIcon}\n menuItems={menuItems}\n rootRef={setNodeRef}\n onOpen={() => onOpen(folder)}\n onToggleSelect={onToggleSelect ? (e) => onToggleSelect(folder, e) : undefined}\n onCommitName={(name) => onCommitName?.(folder, name)}\n onCancelName={onCancelName}\n />\n )\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["FileTile", "FolderTile"]
|
|
7
7
|
}
|
|
@@ -39,7 +39,7 @@ const READ_ONLY_FIELDS = {
|
|
|
39
39
|
n_pages: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.n_pages || "N/A" }),
|
|
40
40
|
created_at: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.created_at ? formatFriendlyDate(doc.created_at) : "N/A" }),
|
|
41
41
|
updated_at: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.updated_at ? formatFriendlyDate(doc.updated_at) : "N/A" }),
|
|
42
|
-
file_type: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: friendlyFileType(doc.file_type, doc.file_name) }),
|
|
42
|
+
file_type: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: friendlyFileType(doc.file_type, doc.file_name, doc.folder) }),
|
|
43
43
|
file_size: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", children: doc.file_size ? `${Math.round(doc.file_size / 1024)} KB` : "N/A" }),
|
|
44
44
|
doc_id: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", isMono: true, children: doc.external_id || "N/A" }),
|
|
45
45
|
content_hash: (doc) => /* @__PURE__ */ jsx(FieldValue, { tone: "muted", isMono: true, isTruncated: true, children: doc.content_hash || "N/A" })
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/connection/files/fields/documentField.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * One field of a document as the review form shows it (a column of the documents table, one per\n * row): its label, icon and the value, editable where the table's column is. Standard fields,\n * metadata, the folder, related documents, the labels and each annotation (with who last set it).\n */\n\nimport type { ElementType, ReactNode } from 'react'\nimport { isAnnotationTag, isLabelTag, type TagResponse } from '@arbidocs/sdk/browser'\nimport type { DocumentPerson, RelatedDocs, WorkspaceDocument } from '@arbidocs/react'\nimport {\n DebouncedInput,\n formatFriendlyDate,\n friendlyFileType,\n Textarea,\n formatDocDate,\n getDocumentDate,\n getDocumentTitle,\n} from '@arbidocs/react/ui'\nimport {\n FieldFolderSelect,\n FieldFolderValue,\n FieldNativeSelect,\n FieldValue,\n FieldWithAttribution,\n} from '../../../files/FieldParts'\nimport { DocumentUser } from './DocumentUser'\nimport {\n DocTagAttribution,\n FolderPicker,\n LabelsCombobox,\n RelatedDocuments,\n} from './DocumentFieldParts'\n\ntype DocTag = NonNullable<WorkspaceDocument['doctags']>[number]\nexport type DocTagCitations = NonNullable<DocTag['citations']> | null\n\n/** A field as the form lays it out. */\nexport interface DocumentFieldContent {\n label: string\n icon?: ReactNode\n /** The annotation the field is (its pill is shown as the label). */\n tag?: TagResponse\n children: ReactNode\n}\n\nexport interface DocumentFieldOptions {\n /** The column (a standard field's id, or an annotation's tag id). */\n columnId: string\n doc: WorkspaceDocument\n canEdit: boolean\n workspaceTags: TagResponse[]\n /** The workspace's documents (the folders to pick from). */\n allDocuments?: WorkspaceDocument[]\n /** Who uploaded the document. */\n creator?: DocumentPerson\n getColumnLabel: (colId: string) => string\n getColumnIcon: (colId: string) => ElementType | undefined\n isColumnEditable: (colId: string) => boolean\n onUpdateDocumentField: (field: string, value: unknown) => void\n onUpdateTagValue: (tag: TagResponse, value: string | boolean) => void\n onUpdateTagWithCitations: (tag: TagResponse, note: string, citations: DocTagCitations) => void\n /** Create a label and apply it (the labels picker). Absent: the picker only toggles. */\n onCreateAndApplyLabel?: (name: string) => void\n /** The document's related documents (email family, copies, duplicates, similar). */\n relatedDocs?: RelatedDocs<WorkspaceDocument>\n /** Open a related document. */\n onOpenDocument?: (docId: string) => void\n /** Delete a related document (asks first). */\n onDeleteDocument?: (docId: string) => void\n canDeleteRelatedDocument?: (doc: WorkspaceDocument) => boolean\n /** Compare with a similar document. Absent: not offered. */\n onCompareDocuments?: (docId: string, otherDocId: string) => void\n}\n\n/** The document metadata a field edits as text. */\nconst METADATA_FIELDS: Record<string, (doc: WorkspaceDocument) => string> = {\n title: (doc) => getDocumentTitle(doc),\n doc_nature: (doc) => doc.doc_metadata?.doc_nature || '',\n doc_author: (doc) => doc.doc_metadata?.doc_author || '',\n doc_subject: (doc) => doc.doc_metadata?.doc_subject || '',\n // As the table shows it: with the time when the value has one (emails).\n doc_date: (doc) => formatDocDate(getDocumentDate(doc)),\n}\n\nconst INPUT_CLASS = 'text-sm bg-muted/40 focus:bg-background transition-colors'\n\n/** A read-only standard field: its value (muted unless said otherwise). */\nconst READ_ONLY_FIELDS: Record<string, (doc: WorkspaceDocument) => ReactNode> = {\n file_name: (doc) => <FieldValue tone=\"strong\">{doc.file_name || 'N/A'}</FieldValue>,\n status: (doc) => <FieldValue tone=\"muted\">{doc.status || 'N/A'}</FieldValue>,\n n_pages: (doc) => <FieldValue tone=\"muted\">{doc.n_pages || 'N/A'}</FieldValue>,\n created_at: (doc) => (\n <FieldValue tone=\"muted\">\n {doc.created_at ? formatFriendlyDate(doc.created_at) : 'N/A'}\n </FieldValue>\n ),\n updated_at: (doc) => (\n <FieldValue tone=\"muted\">\n {doc.updated_at ? formatFriendlyDate(doc.updated_at) : 'N/A'}\n </FieldValue>\n ),\n file_type: (doc) => (\n <FieldValue tone=\"muted\"
|
|
5
|
-
"mappings": ";AAwFsB;AAjFtB,SAAS,iBAAiB,kBAAoC;AAE9D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA4CP,MAAM,kBAAsE;AAAA,EAC1E,OAAO,CAAC,QAAQ,iBAAiB,GAAG;AAAA,EACpC,YAAY,CAAC,QAAQ,IAAI,cAAc,cAAc;AAAA,EACrD,YAAY,CAAC,QAAQ,IAAI,cAAc,cAAc;AAAA,EACrD,aAAa,CAAC,QAAQ,IAAI,cAAc,eAAe;AAAA;AAAA,EAEvD,UAAU,CAAC,QAAQ,cAAc,gBAAgB,GAAG,CAAC;AACvD;AAEA,MAAM,cAAc;AAGpB,MAAM,mBAA0E;AAAA,EAC9E,WAAW,CAAC,QAAQ,oBAAC,cAAW,MAAK,UAAU,cAAI,aAAa,OAAM;AAAA,EACtE,QAAQ,CAAC,QAAQ,oBAAC,cAAW,MAAK,SAAS,cAAI,UAAU,OAAM;AAAA,EAC/D,SAAS,CAAC,QAAQ,oBAAC,cAAW,MAAK,SAAS,cAAI,WAAW,OAAM;AAAA,EACjE,YAAY,CAAC,QACX,oBAAC,cAAW,MAAK,SACd,cAAI,aAAa,mBAAmB,IAAI,UAAU,IAAI,OACzD;AAAA,EAEF,YAAY,CAAC,QACX,oBAAC,cAAW,MAAK,SACd,cAAI,aAAa,mBAAmB,IAAI,UAAU,IAAI,OACzD;AAAA,EAEF,WAAW,CAAC,QACV,oBAAC,cAAW,MAAK,
|
|
4
|
+
"sourcesContent": ["/**\n * One field of a document as the review form shows it (a column of the documents table, one per\n * row): its label, icon and the value, editable where the table's column is. Standard fields,\n * metadata, the folder, related documents, the labels and each annotation (with who last set it).\n */\n\nimport type { ElementType, ReactNode } from 'react'\nimport { isAnnotationTag, isLabelTag, type TagResponse } from '@arbidocs/sdk/browser'\nimport type { DocumentPerson, RelatedDocs, WorkspaceDocument } from '@arbidocs/react'\nimport {\n DebouncedInput,\n formatFriendlyDate,\n friendlyFileType,\n Textarea,\n formatDocDate,\n getDocumentDate,\n getDocumentTitle,\n} from '@arbidocs/react/ui'\nimport {\n FieldFolderSelect,\n FieldFolderValue,\n FieldNativeSelect,\n FieldValue,\n FieldWithAttribution,\n} from '../../../files/FieldParts'\nimport { DocumentUser } from './DocumentUser'\nimport {\n DocTagAttribution,\n FolderPicker,\n LabelsCombobox,\n RelatedDocuments,\n} from './DocumentFieldParts'\n\ntype DocTag = NonNullable<WorkspaceDocument['doctags']>[number]\nexport type DocTagCitations = NonNullable<DocTag['citations']> | null\n\n/** A field as the form lays it out. */\nexport interface DocumentFieldContent {\n label: string\n icon?: ReactNode\n /** The annotation the field is (its pill is shown as the label). */\n tag?: TagResponse\n children: ReactNode\n}\n\nexport interface DocumentFieldOptions {\n /** The column (a standard field's id, or an annotation's tag id). */\n columnId: string\n doc: WorkspaceDocument\n canEdit: boolean\n workspaceTags: TagResponse[]\n /** The workspace's documents (the folders to pick from). */\n allDocuments?: WorkspaceDocument[]\n /** Who uploaded the document. */\n creator?: DocumentPerson\n getColumnLabel: (colId: string) => string\n getColumnIcon: (colId: string) => ElementType | undefined\n isColumnEditable: (colId: string) => boolean\n onUpdateDocumentField: (field: string, value: unknown) => void\n onUpdateTagValue: (tag: TagResponse, value: string | boolean) => void\n onUpdateTagWithCitations: (tag: TagResponse, note: string, citations: DocTagCitations) => void\n /** Create a label and apply it (the labels picker). Absent: the picker only toggles. */\n onCreateAndApplyLabel?: (name: string) => void\n /** The document's related documents (email family, copies, duplicates, similar). */\n relatedDocs?: RelatedDocs<WorkspaceDocument>\n /** Open a related document. */\n onOpenDocument?: (docId: string) => void\n /** Delete a related document (asks first). */\n onDeleteDocument?: (docId: string) => void\n canDeleteRelatedDocument?: (doc: WorkspaceDocument) => boolean\n /** Compare with a similar document. Absent: not offered. */\n onCompareDocuments?: (docId: string, otherDocId: string) => void\n}\n\n/** The document metadata a field edits as text. */\nconst METADATA_FIELDS: Record<string, (doc: WorkspaceDocument) => string> = {\n title: (doc) => getDocumentTitle(doc),\n doc_nature: (doc) => doc.doc_metadata?.doc_nature || '',\n doc_author: (doc) => doc.doc_metadata?.doc_author || '',\n doc_subject: (doc) => doc.doc_metadata?.doc_subject || '',\n // As the table shows it: with the time when the value has one (emails).\n doc_date: (doc) => formatDocDate(getDocumentDate(doc)),\n}\n\nconst INPUT_CLASS = 'text-sm bg-muted/40 focus:bg-background transition-colors'\n\n/** A read-only standard field: its value (muted unless said otherwise). */\nconst READ_ONLY_FIELDS: Record<string, (doc: WorkspaceDocument) => ReactNode> = {\n file_name: (doc) => <FieldValue tone=\"strong\">{doc.file_name || 'N/A'}</FieldValue>,\n status: (doc) => <FieldValue tone=\"muted\">{doc.status || 'N/A'}</FieldValue>,\n n_pages: (doc) => <FieldValue tone=\"muted\">{doc.n_pages || 'N/A'}</FieldValue>,\n created_at: (doc) => (\n <FieldValue tone=\"muted\">\n {doc.created_at ? formatFriendlyDate(doc.created_at) : 'N/A'}\n </FieldValue>\n ),\n updated_at: (doc) => (\n <FieldValue tone=\"muted\">\n {doc.updated_at ? formatFriendlyDate(doc.updated_at) : 'N/A'}\n </FieldValue>\n ),\n file_type: (doc) => (\n <FieldValue tone=\"muted\">\n {friendlyFileType(doc.file_type, doc.file_name, doc.folder)}\n </FieldValue>\n ),\n file_size: (doc) => (\n <FieldValue tone=\"muted\">\n {doc.file_size ? `${Math.round(doc.file_size / 1024)} KB` : 'N/A'}\n </FieldValue>\n ),\n doc_id: (doc) => (\n <FieldValue tone=\"muted\" isMono>\n {doc.external_id || 'N/A'}\n </FieldValue>\n ),\n content_hash: (doc) => (\n <FieldValue tone=\"muted\" isMono isTruncated>\n {doc.content_hash || 'N/A'}\n </FieldValue>\n ),\n}\n\n/** The field of `columnId`, or null when the document has none to show there. */\nexport function documentFieldContent(options: DocumentFieldOptions): DocumentFieldContent | null {\n const { columnId, doc, canEdit, workspaceTags, getColumnLabel, getColumnIcon } = options\n const Icon = getColumnIcon(columnId)\n const standard = (children: ReactNode): DocumentFieldContent => ({\n label: getColumnLabel(columnId),\n icon: Icon ? <Icon size={14} /> : undefined,\n children,\n })\n\n const metadata = METADATA_FIELDS[columnId]\n if (metadata) {\n const editable = options.isColumnEditable(columnId) && canEdit\n return standard(\n editable ? (\n <DebouncedInput\n value={metadata(doc)}\n onChange={(value) => options.onUpdateDocumentField(columnId, value)}\n multiline={true}\n placeholder={`Add ${getColumnLabel(columnId).toLowerCase()}\u2026`}\n className={INPUT_CLASS}\n />\n ) : (\n <FieldValue>{metadata(doc) || 'N/A'}</FieldValue>\n )\n )\n }\n\n const readOnly = READ_ONLY_FIELDS[columnId]\n if (readOnly) return standard(readOnly(doc))\n\n if (columnId === 'created_by') return standard(<DocumentUser user={options.creator} />)\n\n if (columnId === 'folder') {\n return standard(\n canEdit ? (\n <FieldFolderSelect\n folder={doc.folder}\n picker={\n <FolderPicker\n documents={options.allDocuments ?? []}\n value={doc.folder}\n onSelect={(folder) => options.onUpdateDocumentField('folder', folder)}\n />\n }\n />\n ) : (\n <FieldFolderValue folder={doc.folder} />\n )\n )\n }\n\n if (columnId === 'related') {\n const related = options.relatedDocs\n if (!related) return null\n return standard(\n <RelatedDocuments\n doc={doc}\n related={related}\n onOpen={options.onOpenDocument}\n onDelete={options.onDeleteDocument}\n canDelete={options.canDeleteRelatedDocument}\n onCompare={options.onCompareDocuments}\n />\n )\n }\n\n if (columnId === 'all_tags') {\n // The labels (and issues), toggled in place.\n const labelTags = workspaceTags.filter(isLabelTag)\n const appliedIds = new Set(\n (doc.doctags ?? [])\n .filter((dt) => labelTags.some((t) => t.external_id === dt.tag_ext_id))\n .map((dt) => dt.tag_ext_id)\n )\n return standard(\n <LabelsCombobox\n labelTags={labelTags}\n appliedTagIds={appliedIds}\n onToggle={(tag) => options.onUpdateTagValue(tag, !appliedIds.has(tag.external_id))}\n onCreateAndApply={options.onCreateAndApplyLabel}\n />\n )\n }\n\n // An annotation (a label is a value of the Labels field, not a field of its own).\n const tag = workspaceTags.find((t) => t.external_id === columnId)\n if (!tag || !isAnnotationTag(tag)) return null\n const doctag = doc.doctags?.find((dt) => dt.tag_ext_id === tag.external_id)\n\n let value: ReactNode\n if (tag.tag_type.type === 'select') {\n value = (\n <FieldNativeSelect\n value={doctag?.note || ''}\n options={tag.tag_type.options}\n onChange={(next) => options.onUpdateTagValue(tag, next)}\n ariaLabel={tag.name}\n />\n )\n } else if (tag.tag_type.type === 'number') {\n value = (\n <DebouncedInput\n type=\"number\"\n value={doctag?.note || ''}\n onChange={(next) => options.onUpdateTagValue(tag, next)}\n placeholder={`Add ${tag.name.toLowerCase()}\u2026`}\n className={INPUT_CLASS}\n />\n )\n } else {\n // A plain note: a value's citations come from generation and are kept as they are.\n value = (\n <Textarea\n value={doctag?.note || ''}\n onChange={(e) =>\n options.onUpdateTagWithCitations(tag, e.target.value, doctag?.citations ?? null)\n }\n placeholder=\"Add a note...\"\n rows={2}\n className={INPUT_CLASS}\n />\n )\n }\n\n return {\n label: tag.name,\n tag,\n children: doctag ? (\n <FieldWithAttribution attribution={<DocTagAttribution doctag={doctag} />}>\n {value}\n </FieldWithAttribution>\n ) : (\n value\n ),\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAwFsB;AAjFtB,SAAS,iBAAiB,kBAAoC;AAE9D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA4CP,MAAM,kBAAsE;AAAA,EAC1E,OAAO,CAAC,QAAQ,iBAAiB,GAAG;AAAA,EACpC,YAAY,CAAC,QAAQ,IAAI,cAAc,cAAc;AAAA,EACrD,YAAY,CAAC,QAAQ,IAAI,cAAc,cAAc;AAAA,EACrD,aAAa,CAAC,QAAQ,IAAI,cAAc,eAAe;AAAA;AAAA,EAEvD,UAAU,CAAC,QAAQ,cAAc,gBAAgB,GAAG,CAAC;AACvD;AAEA,MAAM,cAAc;AAGpB,MAAM,mBAA0E;AAAA,EAC9E,WAAW,CAAC,QAAQ,oBAAC,cAAW,MAAK,UAAU,cAAI,aAAa,OAAM;AAAA,EACtE,QAAQ,CAAC,QAAQ,oBAAC,cAAW,MAAK,SAAS,cAAI,UAAU,OAAM;AAAA,EAC/D,SAAS,CAAC,QAAQ,oBAAC,cAAW,MAAK,SAAS,cAAI,WAAW,OAAM;AAAA,EACjE,YAAY,CAAC,QACX,oBAAC,cAAW,MAAK,SACd,cAAI,aAAa,mBAAmB,IAAI,UAAU,IAAI,OACzD;AAAA,EAEF,YAAY,CAAC,QACX,oBAAC,cAAW,MAAK,SACd,cAAI,aAAa,mBAAmB,IAAI,UAAU,IAAI,OACzD;AAAA,EAEF,WAAW,CAAC,QACV,oBAAC,cAAW,MAAK,SACd,2BAAiB,IAAI,WAAW,IAAI,WAAW,IAAI,MAAM,GAC5D;AAAA,EAEF,WAAW,CAAC,QACV,oBAAC,cAAW,MAAK,SACd,cAAI,YAAY,GAAG,KAAK,MAAM,IAAI,YAAY,IAAI,CAAC,QAAQ,OAC9D;AAAA,EAEF,QAAQ,CAAC,QACP,oBAAC,cAAW,MAAK,SAAQ,QAAM,MAC5B,cAAI,eAAe,OACtB;AAAA,EAEF,cAAc,CAAC,QACb,oBAAC,cAAW,MAAK,SAAQ,QAAM,MAAC,aAAW,MACxC,cAAI,gBAAgB,OACvB;AAEJ;AAGO,SAAS,qBAAqB,SAA4D;AAC/F,QAAM,EAAE,UAAU,KAAK,SAAS,eAAe,gBAAgB,cAAc,IAAI;AACjF,QAAM,OAAO,cAAc,QAAQ;AACnC,QAAM,WAAW,CAAC,cAA+C;AAAA,IAC/D,OAAO,eAAe,QAAQ;AAAA,IAC9B,MAAM,OAAO,oBAAC,QAAK,MAAM,IAAI,IAAK;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,WAAW,gBAAgB,QAAQ;AACzC,MAAI,UAAU;AACZ,UAAM,WAAW,QAAQ,iBAAiB,QAAQ,KAAK;AACvD,WAAO;AAAA,MACL,WACE;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,SAAS,GAAG;AAAA,UACnB,UAAU,CAACA,WAAU,QAAQ,sBAAsB,UAAUA,MAAK;AAAA,UAClE,WAAW;AAAA,UACX,aAAa,OAAO,eAAe,QAAQ,EAAE,YAAY,CAAC;AAAA,UAC1D,WAAW;AAAA;AAAA,MACb,IAEA,oBAAC,cAAY,mBAAS,GAAG,KAAK,OAAM;AAAA,IAExC;AAAA,EACF;AAEA,QAAM,WAAW,iBAAiB,QAAQ;AAC1C,MAAI,SAAU,QAAO,SAAS,SAAS,GAAG,CAAC;AAE3C,MAAI,aAAa,aAAc,QAAO,SAAS,oBAAC,gBAAa,MAAM,QAAQ,SAAS,CAAE;AAEtF,MAAI,aAAa,UAAU;AACzB,WAAO;AAAA,MACL,UACE;AAAA,QAAC;AAAA;AAAA,UACC,QAAQ,IAAI;AAAA,UACZ,QACE;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,QAAQ,gBAAgB,CAAC;AAAA,cACpC,OAAO,IAAI;AAAA,cACX,UAAU,CAAC,WAAW,QAAQ,sBAAsB,UAAU,MAAM;AAAA;AAAA,UACtE;AAAA;AAAA,MAEJ,IAEA,oBAAC,oBAAiB,QAAQ,IAAI,QAAQ;AAAA,IAE1C;AAAA,EACF;AAEA,MAAI,aAAa,WAAW;AAC1B,UAAM,UAAU,QAAQ;AACxB,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO;AAAA,MACL;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,QAAQ,QAAQ;AAAA,UAChB,UAAU,QAAQ;AAAA,UAClB,WAAW,QAAQ;AAAA,UACnB,WAAW,QAAQ;AAAA;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,aAAa,YAAY;AAE3B,UAAM,YAAY,cAAc,OAAO,UAAU;AACjD,UAAM,aAAa,IAAI;AAAA,OACpB,IAAI,WAAW,CAAC,GACd,OAAO,CAAC,OAAO,UAAU,KAAK,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAAC,EACrE,IAAI,CAAC,OAAO,GAAG,UAAU;AAAA,IAC9B;AACA,WAAO;AAAA,MACL;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,eAAe;AAAA,UACf,UAAU,CAACC,SAAQ,QAAQ,iBAAiBA,MAAK,CAAC,WAAW,IAAIA,KAAI,WAAW,CAAC;AAAA,UACjF,kBAAkB,QAAQ;AAAA;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAGA,QAAM,MAAM,cAAc,KAAK,CAAC,MAAM,EAAE,gBAAgB,QAAQ;AAChE,MAAI,CAAC,OAAO,CAAC,gBAAgB,GAAG,EAAG,QAAO;AAC1C,QAAM,SAAS,IAAI,SAAS,KAAK,CAAC,OAAO,GAAG,eAAe,IAAI,WAAW;AAE1E,MAAI;AACJ,MAAI,IAAI,SAAS,SAAS,UAAU;AAClC,YACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,QAAQ,QAAQ;AAAA,QACvB,SAAS,IAAI,SAAS;AAAA,QACtB,UAAU,CAAC,SAAS,QAAQ,iBAAiB,KAAK,IAAI;AAAA,QACtD,WAAW,IAAI;AAAA;AAAA,IACjB;AAAA,EAEJ,WAAW,IAAI,SAAS,SAAS,UAAU;AACzC,YACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAO,QAAQ,QAAQ;AAAA,QACvB,UAAU,CAAC,SAAS,QAAQ,iBAAiB,KAAK,IAAI;AAAA,QACtD,aAAa,OAAO,IAAI,KAAK,YAAY,CAAC;AAAA,QAC1C,WAAW;AAAA;AAAA,IACb;AAAA,EAEJ,OAAO;AAEL,YACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,QAAQ,QAAQ;AAAA,QACvB,UAAU,CAAC,MACT,QAAQ,yBAAyB,KAAK,EAAE,OAAO,OAAO,QAAQ,aAAa,IAAI;AAAA,QAEjF,aAAY;AAAA,QACZ,MAAM;AAAA,QACN,WAAW;AAAA;AAAA,IACb;AAAA,EAEJ;AAEA,SAAO;AAAA,IACL,OAAO,IAAI;AAAA,IACX;AAAA,IACA,UAAU,SACR,oBAAC,wBAAqB,aAAa,oBAAC,qBAAkB,QAAgB,GACnE,iBACH,IAEA;AAAA,EAEJ;AACF;",
|
|
6
6
|
"names": ["value", "tag"]
|
|
7
7
|
}
|
|
@@ -406,7 +406,7 @@ function createDocumentColumns({
|
|
|
406
406
|
filter: "agTextColumnFilter",
|
|
407
407
|
filterParams: FILTER_PARAMS,
|
|
408
408
|
context: { icon: FileType },
|
|
409
|
-
valueGetter: (params) => friendlyFileType(params.data?.file_type, params.data?.file_name)
|
|
409
|
+
valueGetter: (params) => friendlyFileType(params.data?.file_type, params.data?.file_name, params.data?.folder)
|
|
410
410
|
});
|
|
411
411
|
allColumns.push({
|
|
412
412
|
colId: "folder",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/connection/files/grid/documentColumns.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * The documents table's columns (explicit `colId`s; AG Grid's saved state decides which show and\n * in what order): the document pill, its status, its AI fields (type, author, abstract, date), its\n * file facts, folder, sender, fingerprint, related documents, visibility, uploader, labels, id, and\n * one column per AI field. Writes come in as parameters, the row-independent lookups through the\n * grid's context, so the columns are rebuilt only when the fields themselves change.\n */\n\nimport type { ColDef, IRowNode } from 'ag-grid-community'\nimport {\n Calendar,\n Clock,\n File,\n FileText,\n FileType,\n Fingerprint,\n FolderOpen,\n Hash,\n HardDrive,\n Link2,\n Mail,\n Paperclip,\n Share2,\n Sparkles,\n Tags,\n Upload,\n User,\n} from 'lucide-react'\nimport {\n formatFileSize,\n isAnnotationTag,\n isLabelTag,\n type TagResponse,\n} from '@arbidocs/sdk/browser'\nimport {\n type DocumentHostActions,\n type RelatedDocsMap,\n type useAssignDocTags,\n type useCreateTag,\n type useRemoveDocTags,\n type useUpdateDocTag,\n} from '@arbidocs/react'\nimport {\n formatDocDate,\n formatFolderLabel,\n formatFriendlyDate,\n friendlyFileType,\n getDocumentAuthor,\n getDocumentDate,\n getDocumentNature,\n getDocumentSubject,\n getDocumentTitle,\n markdownToPlainText,\n} from '@arbidocs/react/ui'\nimport { DOCUMENT_TYPE_OPTIONS } from '../../../files/documentColumns'\nimport {\n canChangeVisibility,\n canEditDocumentFields,\n type WorkspaceMemberRole,\n} from '../../../files/permissions'\nimport type { FileTileDocument } from '../explorer/FileTiles'\nimport type { GridUser } from './cells'\nimport {\n CreatedByCellRenderer,\n DocumentNameCellRenderer,\n FolderCellRenderer,\n LabelsCellRenderer,\n RelatedDocsCellRenderer,\n SharedCellRenderer,\n StatusCellRenderer,\n type DocumentNameCellParams,\n type FolderCellParams,\n type LabelsCellParams,\n type RelatedDocsCellParams,\n type SharedCellParams,\n type StatusCellParams,\n} from './documentCellRenderers'\nimport { createTagColumn } from './tagColumn'\n\n/** A row of the documents table. */\nexport type GridDocument = FileTileDocument & {\n /** The email sender of a document imported from mail (\"Ada <ada@x.com>\"). */\n sender?: string | null\n}\n\ntype Doc = GridDocument\ntype Tag = TagResponse\n\n/**\n * What the columns read through the grid's `context` (row-independent, so the column definitions\n * stay put when they change).\n */\nexport interface DocumentGridContext {\n getDocuments?: () => GridDocument[]\n getRelatedDocs?: () => RelatedDocsMap<GridDocument>\n getFamilyMeta?: () => Map<string, { tier: number; count: number }>\n getWorkspaceUsers?: () => GridUser[]\n getCurrentUserId?: () => string | undefined\n getViewingDocumentId?: () => string | null\n getHostActions?: () => DocumentHostActions\n updateFolder?: (docId: string, folder: string | null) => void\n}\n\n// Stable filter params object (reused across all filter columns)\nconst FILTER_PARAMS = {\n buttons: ['reset', 'apply'] as const,\n closeOnApply: true,\n}\n\nexport interface CreateDocumentColumnsParams {\n handleToggleDocumentViewer: (docId: string) => void\n onStatusClick?: () => void\n /** Per-row document actions for the unified name column's \u22EF kebab. */\n onReviewDocument?: (docId: string) => void\n /** Start a new chat scoped to one document, opening it in the side viewer. */\n onDocumentChat?: (docId: string) => void\n onDownloadDocument?: (doc: Doc) => void\n onMoveDocument?: (docId: string) => void\n onDeleteDocument?: (docId: string) => void\n isMember: boolean\n /**\n * The viewer's role in the workspace (null: not a member, e.g. a public workspace's visitor).\n * Only an owner or a collaborator edits documents someone else created.\n */\n workspaceRole: WorkspaceMemberRole | null\n currentUserExtId?: string\n availableTags: Tag[]\n createDocTag: Pick<ReturnType<typeof useAssignDocTags>, 'mutateAsync'>\n updateDocTag: Pick<ReturnType<typeof useUpdateDocTag>, 'mutateAsync'>\n deleteDocTag: Pick<ReturnType<typeof useRemoveDocTags>, 'mutateAsync'>\n createTag: Pick<ReturnType<typeof useCreateTag>, 'mutateAsync'>\n /** Share a document with the workspace, or make it private. */\n onToggleShared: (docId: string, shared: boolean) => void\n /** How a tag write's outcome is told (the environment's notify). */\n notify: (message: string, kind: 'success' | 'error') => void\n}\n\nexport function createDocumentColumns({\n handleToggleDocumentViewer,\n onStatusClick,\n onReviewDocument,\n onDocumentChat,\n onDownloadDocument,\n onMoveDocument,\n onDeleteDocument,\n isMember,\n workspaceRole,\n currentUserExtId,\n availableTags,\n createDocTag,\n updateDocTag,\n deleteDocTag,\n createTag,\n onToggleShared,\n notify,\n}: CreateDocumentColumnsParams): ColDef<Doc>[] {\n // Owner/creator check \u2014 the sole gate for the privacy/visibility toggle.\n const isRowEditableByOwner = (params: { data?: Doc | null }): boolean =>\n canChangeVisibility(params.data, currentUserExtId)\n\n // Regular fields: see canEditDocumentFields (shared with the detail pane).\n const isRowEditableByMember = (params: { data?: Doc | null }): boolean =>\n canEditDocumentFields(params.data, currentUserExtId, workspaceRole)\n\n const checkboxTags = availableTags.filter(isLabelTag)\n\n const allColumns: ColDef<Doc>[] = []\n\n // Status column - shows status indicator (checkmark, error, progress bar)\n allColumns.push({\n colId: 'status',\n headerName: 'Status',\n field: 'status',\n // Wide enough for the full \"Status\" header (plus its sort indicator) to show\n // without truncating. suppressSizeToFit so it doesn't grow to fill space.\n width: 144,\n minWidth: 128,\n suppressSizeToFit: true,\n sortable: true,\n cellDataType: 'text',\n context: { icon: Paperclip },\n valueGetter: (params) => {\n if (!params.data) return null\n return params.data.status?.toLowerCase() ?? null\n },\n comparator: (\n a: string | null,\n b: string | null,\n nodeA: IRowNode<Doc>,\n nodeB: IRowNode<Doc>\n ) => {\n const STATUS_ORDER: Record<string, number> = {\n queued: 0,\n parsing: 1,\n encrypting: 2,\n indexing: 3,\n analysing: 4,\n completed: 5,\n 'low-content': 6,\n empty: 7,\n skipped: 8,\n failed: 9,\n }\n const rankA = a != null ? (STATUS_ORDER[a] ?? 10) : 10\n const rankB = b != null ? (STATUS_ORDER[b] ?? 10) : 10\n if (rankA !== rankB) return rankA - rankB\n // Secondary sort: within 'failed', order by pipeline stage\n if (a === 'failed' && b === 'failed') {\n const STAGE_ORDER: Record<string, number> = {\n parsing: 0,\n encrypting: 1,\n indexing: 2,\n analysing: 3,\n queued: 4,\n unknown: 5,\n }\n const stageA = nodeA.data?.failed_stage ?? null\n const stageB = nodeB.data?.failed_stage ?? null\n const stageRankA = stageA != null ? (STAGE_ORDER[stageA] ?? 6) : 7\n const stageRankB = stageB != null ? (STAGE_ORDER[stageB] ?? 6) : 7\n return stageRankA - stageRankB\n }\n return 0\n },\n cellRenderer: StatusCellRenderer,\n cellRendererParams: { onStatusClick } satisfies StatusCellParams,\n // Status is a single icon \u2014 center it horizontally (header + cell) rather\n // than left-aligning a lone glyph against the column edge. `cell-status`\n // trims the cell's vertical padding so the progress bar + label fit (and sit\n // near the top) even at the minimum row height.\n cellClass: 'cell-hcenter cell-status',\n headerClass: 'header-hcenter',\n })\n\n // (The per-row \"In Chat\" toggle column was removed \u2014 adding documents to the\n // current chat is now done via the bulk-actions toolbar after selecting rows.)\n\n // Document Name column\n // Unified Document column: entity badge (icon + title) opens the doc on click;\n // a hover \u22EF kebab carries the row actions (incl. Rename \u2014 no inline pencil).\n // Stays editable so the kebab's Rename can trigger the inline title editor;\n // edit is double-click / kebab only (not single-click, which opens).\n allColumns.push({\n colId: 'title',\n headerName: 'Title',\n // `initialFlex` (not `flex`): a stateful `flex` gets re-asserted every time\n // AG Grid re-processes the column definitions \u2014 which happens on many host\n // re-renders, including the one triggered by persisting the grid state\n // right after a manual resize \u2014 recomputing Title back to fill the leftover\n // space and snapping away the user's drag. With initialFlex the fill only\n // applies when the column is first created; after that a manual resize\n // sticks. The 160px floor lets the phone's Title + Status list fit 390px without sideways scroll.\n initialFlex: 3,\n minWidth: isPhoneViewport() ? 160 : 280,\n // Title is intentionally NOT pinned on mount: the default layout wants the\n // row-select checkbox as the first column with Title second. AG Grid always\n // renders pinned-left columns ahead of unpinned ones, so pinning Title (while\n // the selection column stays unpinned) pushed Title into the first slot,\n // ahead of the checkbox. Leaving it unpinned matches the built-in \"Default\n // view\" (which unpins everything) and lets the selection column sit first.\n // The \"Document view\" still pins the checkbox + Title left for users who want\n // the name frozen while scrolling the many data columns.\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n editable: isRowEditableByMember,\n cellEditor: 'agLargeTextCellEditor',\n cellEditorPopup: true,\n cellEditorParams: { rows: 5, cols: 50 },\n context: { icon: FileText },\n cellRenderer: DocumentNameCellRenderer,\n cellRendererParams: {\n canEdit: isRowEditableByMember,\n onOpenDocument: handleToggleDocumentViewer,\n onReviewDocument,\n onDocumentChat,\n onDownloadDocument,\n onMoveDocument,\n onDeleteDocument,\n } satisfies DocumentNameCellParams,\n valueGetter: (params) => getDocumentTitle(params.data, 'Untitled'),\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.title = params.newValue\n return true\n },\n // No AG Grid tooltip here \u2014 the DocumentEntity pill renders its own\n // AI-summary hover card (same one the explorer tiles use). A\n // tooltipValueGetter would stack a second, plain title tooltip on top.\n })\n\n // Document Type column (AI-generated, user-editable dropdown)\n // Options from DOCUMENT_TYPE_OPTIONS constant (synced with backend DocTagLLM.DEFAULT_METADATA_TAGS)\n allColumns.push({\n colId: 'doc_nature',\n headerName: 'Type',\n width: 120,\n minWidth: 100,\n sortable: true,\n filter: 'agTextColumnFilter',\n editable: isRowEditableByMember,\n singleClickEdit: true,\n cellEditor: 'agSelectCellEditor',\n cellEditorParams: {\n values: [...DOCUMENT_TYPE_OPTIONS],\n },\n context: { icon: Sparkles },\n valueGetter: (params) => getDocumentNature(params.data) || '',\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_nature = params.newValue || null\n return true\n },\n // Show dropdown indicator for editable cells (no custom renderer for performance)\n cellClass: (params) =>\n isRowEditableByMember(params) ? 'cell-select-editable' : 'cell-editable-readonly relative',\n })\n\n // Document Author column (AI-generated, user-editable)\n allColumns.push({\n colId: 'doc_author',\n headerName: 'Author',\n width: 150,\n minWidth: 100,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n editable: isRowEditableByMember,\n singleClickEdit: true,\n cellEditor: 'agLargeTextCellEditor',\n cellEditorPopup: true,\n cellEditorParams: { rows: 3, cols: 40 },\n context: { icon: User },\n valueGetter: (params) => getDocumentAuthor(params.data) || '',\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_author = params.newValue || null\n return true\n },\n tooltipValueGetter: (params) => getDocumentAuthor(params.data) || '',\n // cell-multiline: wrap long author lists to as many lines as the current\n // row height allows (same height-driven clamp as Abstract).\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative cell-multiline'\n : 'cell-editable-readonly relative cell-multiline',\n })\n\n // Document Abstract column (AI-generated, user-editable)\n allColumns.push({\n colId: 'doc_subject',\n headerName: 'Abstract',\n width: 300,\n minWidth: 200,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n editable: isRowEditableByMember,\n singleClickEdit: true,\n cellEditor: 'agLargeTextCellEditor',\n cellEditorPopup: true,\n cellEditorParams: { rows: 8, cols: 60 },\n context: { icon: FileText },\n // Edit against the raw markdown (so the large-text editor shows the real\n // source), but display a flattened plain-text preview in the cell and\n // tooltip \u2014 our AI summaries often contain markdown bullets/emphasis, and\n // rendering raw markers (\"* \u2026\", \"**\u2026**\") in a dense cell reads as noise.\n // markdownToPlainText is a cheap string transform run only on visible cells.\n valueGetter: (params) => getDocumentSubject(params.data) || '',\n valueFormatter: (params) => markdownToPlainText(params.value),\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_subject = params.newValue || null\n return true\n },\n tooltipValueGetter: (params) => markdownToPlainText(getDocumentSubject(params.data)),\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative cell-multiline'\n : 'cell-editable-readonly relative cell-multiline',\n })\n\n // Date column\n // Optimized: Using AG Grid's built-in editing + CSS-only hover icons (no React cellRenderer)\n allColumns.push({\n colId: 'doc_date',\n headerName: 'Date',\n width: 160,\n minWidth: 150, // Wider to fit an optional time (emails carry date + time)\n sortable: true,\n editable: isRowEditableByMember,\n singleClickEdit: true,\n context: { icon: Calendar },\n valueGetter: (params) => getDocumentDate(params.data),\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_date = params.newValue\n return true\n },\n valueFormatter: (params) => {\n if (!params.value) return '\u2014'\n return formatDocDate(params.value)\n },\n // Ensure text doesn't overflow - use cellStyle for overflow handling\n cellStyle: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n // Add Tailwind classes + CSS class for hover icon (pencil if editable, ban if not)\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative cell-tnum'\n : 'cell-editable-readonly relative cell-tnum',\n // Date filter with a start/end range (date-only comparison; ignores any time).\n filter: 'agDateColumnFilter',\n filterParams: {\n browserDatePicker: true,\n inRangeInclusive: true,\n // cellValue is the raw doc_date string (date or datetime); compare date-only.\n comparator: (filterDate: Date, cellValue: string | null) => {\n if (!cellValue) return -1\n const d = new Date(cellValue)\n if (Number.isNaN(d.getTime())) return -1\n const cellDay = new Date(d.getFullYear(), d.getMonth(), d.getDate())\n if (cellDay < filterDate) return -1\n if (cellDay > filterDate) return 1\n return 0\n },\n },\n // No valueParser - let user type freely without validation interrupting\n // Validation happens in onCellValueChanged after editing completes\n // No cellRenderer - AG Grid handles rendering natively with valueFormatter\n })\n\n // Pages column\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'n_pages',\n headerName: 'Pages',\n field: 'n_pages',\n width: 100,\n sortable: true,\n cellDataType: 'number',\n cellClass: 'cell-numeric',\n context: { icon: Hash },\n valueGetter: (params) => {\n return params.data?.n_pages || null\n },\n valueFormatter: (params) => {\n if (params.value === null || params.value === undefined) return '\u2014'\n return params.value.toLocaleString()\n },\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // Upload date column - just the date, sortable by date\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'created_at',\n headerName: 'Uploaded',\n field: 'created_at',\n width: 160,\n sortable: true,\n filter: 'agDateColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Upload },\n valueFormatter: (params) => {\n if (!params.value) return '\u2014'\n return formatFriendlyDate(params.value)\n },\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // Last modified column\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'updated_at',\n headerName: 'Last modified',\n field: 'updated_at',\n width: 160,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n filter: 'agDateColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Clock },\n valueFormatter: (params) => {\n if (!params.value) return '\u2014'\n return formatFriendlyDate(params.value)\n },\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // File name column\n // Optimized: Using native rendering - no cellRenderer needed for simple text\n allColumns.push({\n colId: 'file_name',\n headerName: 'File name',\n field: 'file_name',\n width: 200,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: File },\n // No cellRenderer - AG Grid handles text rendering natively\n })\n\n // Size column\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'file_size',\n headerName: 'Size',\n field: 'file_size',\n width: 100,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n cellDataType: 'number',\n cellClass: 'cell-numeric',\n context: { icon: HardDrive },\n valueFormatter: (params) => formatFileSize(params.value),\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // File type column.\n //\n // Backend stores ``file_type`` as either a bare extension (``\"pdf\"``)\n // or a full MIME type (``\"application/pdf\"``) depending on which\n // upload path produced the row, so we never render the raw value.\n // ``valueGetter`` runs once per row to produce the friendly label \u2014\n // sort and the text filter then operate on that label, which is what\n // the user actually sees.\n allColumns.push({\n colId: 'file_type',\n headerName: 'File type',\n field: 'file_type',\n width: 120,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: FileType },\n valueGetter: (params) => friendlyFileType(params.data?.file_type, params.data?.file_name),\n })\n\n // Folder column\n allColumns.push({\n colId: 'folder',\n headerName: 'Folder',\n field: 'folder',\n width: 180,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: FolderOpen },\n valueFormatter: (params) => formatFolderLabel(params.value),\n cellRenderer: FolderCellRenderer,\n cellRendererParams: { canEdit: isRowEditableByMember } satisfies FolderCellParams,\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative'\n : 'cell-editable-readonly relative',\n })\n\n // From column \u2014 email sender for connector-imported docs (e.g.\n // \"John Smith <john@x.com>\"). Plain text; null for non-email docs.\n allColumns.push({\n colId: 'sender',\n headerName: 'From',\n field: 'sender',\n width: 180,\n minWidth: 100,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Mail },\n valueGetter: (params) => params.data?.sender ?? '',\n tooltipValueGetter: (params) => params.data?.sender ?? '',\n // No cellRenderer - AG Grid handles text rendering natively\n })\n\n // Content Hash column\n allColumns.push({\n colId: 'content_hash',\n headerName: 'Fingerprint',\n field: 'content_hash',\n width: 200,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Fingerprint },\n cellStyle: { fontFamily: 'monospace' },\n valueFormatter: (params) => params.value || '',\n })\n\n // Related documents column \u2014 shows parent, children, duplicates, similar docs.\n //\n // Tiered sort key (string-compared by AG Grid; defaults to descending so\n // the first header click pulls the most-relevant tier to the top):\n //\n // {tier}|{paddedCount}|{groupId}|{rank}|{external_id}\n //\n // - tier (single digit, higher = top under desc):\n // 3 family has any duplicates\n // 2 family has any similar (no dupes)\n // 1 pure parent/child family (no dupes, no similar)\n // 0 no relationships at all\n // Family tier is computed once per groupId in Documents.tsx so every\n // member of a family shares the same prefix and stays clustered.\n // - paddedCount: aggregate count for the tier, zero-padded to 6 chars\n // so a lexical compare matches a numeric one.\n // - groupId: parent_ext_id for children, own external_id for parents\n // and lone docs, content_hash for standalone duplicate clusters.\n // - rank: 0 for parent/standalone, 1 for children \u2192 parent sorts above\n // its children within a family.\n // - external_id: stable tiebreaker.\n allColumns.push({\n colId: 'related',\n headerName: 'Related',\n width: 200,\n minWidth: 120,\n sortable: true,\n sortingOrder: ['desc', 'asc', null],\n context: { icon: Link2 },\n valueGetter: (params) => {\n if (!params.data) return ''\n const doc = params.data\n const context = params.context as DocumentGridContext | undefined\n const map = context?.getRelatedDocs?.()\n const familyMeta = context?.getFamilyMeta?.()\n const related = map?.get(doc.external_id)\n const isChild = !!doc.parent_ext_id\n const isParent = related?.children && related.children.length > 0\n\n let groupId: string\n let rank: number\n\n if (isChild) {\n // Child: group under parent, rank 1 so parent sorts first\n groupId = doc.parent_ext_id!\n rank = 1\n } else if (isParent) {\n // Parent: group under self, rank 0\n groupId = doc.external_id\n rank = 0\n } else if (doc.content_hash && related && related.duplicates.length > 0) {\n // Standalone duplicate: group by fingerprint\n groupId = doc.content_hash\n rank = 0\n } else {\n // No relationships: sort by own ID\n groupId = doc.external_id\n rank = 0\n }\n\n const meta = familyMeta?.get(groupId) ?? { tier: 0, count: 0 }\n const paddedCount = String(meta.count).padStart(6, '0')\n\n return `${meta.tier}|${paddedCount}|${groupId}|${rank}|${doc.external_id}`\n },\n cellRenderer: RelatedDocsCellRenderer,\n cellRendererParams: {\n onOpenDocument: handleToggleDocumentViewer,\n onDeleteDocument,\n } satisfies RelatedDocsCellParams,\n })\n\n // Shared column\n // Note: Keeping SharedCell for interactive toggle (complex UI)\n allColumns.push({\n colId: 'shared',\n headerName: 'Sharing',\n field: 'shared',\n width: 124,\n minWidth: 124,\n sortable: true,\n cellDataType: 'boolean',\n context: { icon: Share2 },\n valueGetter: (params) => {\n return params.data?.shared ?? false\n },\n cellRenderer: SharedCellRenderer,\n cellRendererParams: {\n canToggle: isRowEditableByOwner,\n onToggleShared,\n } satisfies SharedCellParams,\n })\n\n // Created by column - shows avatar icon (the members come through the grid's context)\n allColumns.push({\n colId: 'created_by',\n headerName: 'By',\n width: 60,\n sortable: true,\n context: { icon: User },\n valueGetter: (params) => {\n if (!params.data) return ''\n const users = (params.context as DocumentGridContext | undefined)?.getWorkspaceUsers?.()\n const creator = users?.find((u) => u.external_id === params.data!.created_by_ext_id)\n if (!creator) return ''\n const fullName = [creator.given_name, creator.family_name].filter(Boolean).join(' ')\n return fullName || creator.email || ''\n },\n cellRenderer: CreatedByCellRenderer,\n })\n\n // Labels column \u2014 shows applied checkbox/label tags as filled checkmarks\n allColumns.push({\n colId: 'all_tags',\n headerName: 'Labels',\n width: 300,\n // Never narrower than its own header (\"Labels\" + filter/menu icons) \u2014 the\n // title must not ellipsize, same floor as the Facts table's Labels column.\n minWidth: 132,\n sortable: false,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Tags },\n valueGetter: (params) => {\n if (!params.data || !params.data.doctags) return ''\n // Only index label (and issue) names for filtering\n const tagNames = params.data.doctags\n .map((dt) => {\n const tag = availableTags.find((t) => t.external_id === dt.tag_ext_id)\n if (!tag || !isLabelTag(tag)) return ''\n return tag.name\n })\n .filter(Boolean)\n return tagNames.join(' ')\n },\n cellRenderer: LabelsCellRenderer,\n cellRendererParams: {\n labels: checkboxTags,\n createDocTag,\n deleteDocTag,\n createTag,\n isMember,\n } satisfies LabelsCellParams,\n // Add CSS class for hover icon (matches title field)\n cellClass: isMember ? 'cell-editable-member relative !pr-0' : 'cell-editable-readonly relative',\n })\n\n // DocID column\n // Optimized: Using valueFormatter for monospace font styling\n // Note: AG Grid doesn't support className in valueFormatter, so we'll use cellStyle instead\n allColumns.push({\n colId: 'doc_id',\n headerName: 'DocID',\n field: 'external_id',\n width: 200,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Hash },\n cellStyle: { fontFamily: 'monospace' },\n // No cellRenderer - native rendering with cellStyle for monospace font\n })\n\n // A column per annotation (labels and issues are in the Labels column)\n const tagColumns = availableTags.filter(isAnnotationTag).map((tag) =>\n createTagColumn({\n tag,\n isMember,\n notify,\n createDocTag,\n updateDocTag,\n deleteDocTag,\n })\n )\n\n // Return ALL columns - AG Grid state controls visibility and order\n return [...allColumns.map(withEmptyDash), ...tagColumns]\n}\n\n/** Title is the most important field, so it gets a wide floor everywhere but a phone. */\nfunction isPhoneViewport(): boolean {\n return (\n typeof window !== 'undefined' && window.matchMedia?.('(max-width: 480px)')?.matches === true\n )\n}\n\n/** Columns whose empty values read as a muted em dash (never a blank cell or an error-like word). */\nconst EMPTY_DASH_COLUMNS: ReadonlySet<string> = new Set([\n 'doc_nature',\n 'doc_author',\n 'doc_subject',\n 'doc_date',\n 'n_pages',\n 'created_at',\n 'updated_at',\n 'file_name',\n 'file_type',\n 'sender',\n])\n\n/** The AI abstract step writes this literal when it finds nothing; to a reader it looks like an error. */\nconst NO_VALUE = /^\\s*(not found|n\\/a)\\.?\\s*$/i\n\nfunction isEmptyCell(value: unknown): boolean {\n return value === null || value === undefined || value === '' || NO_VALUE.test(String(value))\n}\n\n/**\n * Show an em dash, in the muted text colour, for empty values of the plain data columns. Formatting\n * only: the underlying value (and what the cell editors start from) is untouched.\n */\nfunction withEmptyDash(col: ColDef<Doc>): ColDef<Doc> {\n if (!col.colId || !EMPTY_DASH_COLUMNS.has(col.colId)) return col\n const { valueFormatter, cellClass } = col\n return {\n ...col,\n valueFormatter: (params) => {\n if (col.colId !== 'n_pages' && isEmptyCell(params.value)) return '\u2014'\n return typeof valueFormatter === 'function'\n ? valueFormatter(params)\n : String(params.value ?? '')\n },\n cellClass: (params) => {\n const base = typeof cellClass === 'function' ? cellClass(params) : cellClass\n const classes = Array.isArray(base) ? base : base ? [base] : []\n return isEmptyCell(params.value) ? [...classes, 'cell-empty'] : classes\n },\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * The documents table's columns (explicit `colId`s; AG Grid's saved state decides which show and\n * in what order): the document pill, its status, its AI fields (type, author, abstract, date), its\n * file facts, folder, sender, fingerprint, related documents, visibility, uploader, labels, id, and\n * one column per AI field. Writes come in as parameters, the row-independent lookups through the\n * grid's context, so the columns are rebuilt only when the fields themselves change.\n */\n\nimport type { ColDef, IRowNode } from 'ag-grid-community'\nimport {\n Calendar,\n Clock,\n File,\n FileText,\n FileType,\n Fingerprint,\n FolderOpen,\n Hash,\n HardDrive,\n Link2,\n Mail,\n Paperclip,\n Share2,\n Sparkles,\n Tags,\n Upload,\n User,\n} from 'lucide-react'\nimport {\n formatFileSize,\n isAnnotationTag,\n isLabelTag,\n type TagResponse,\n} from '@arbidocs/sdk/browser'\nimport {\n type DocumentHostActions,\n type RelatedDocsMap,\n type useAssignDocTags,\n type useCreateTag,\n type useRemoveDocTags,\n type useUpdateDocTag,\n} from '@arbidocs/react'\nimport {\n formatDocDate,\n formatFolderLabel,\n formatFriendlyDate,\n friendlyFileType,\n getDocumentAuthor,\n getDocumentDate,\n getDocumentNature,\n getDocumentSubject,\n getDocumentTitle,\n markdownToPlainText,\n} from '@arbidocs/react/ui'\nimport { DOCUMENT_TYPE_OPTIONS } from '../../../files/documentColumns'\nimport {\n canChangeVisibility,\n canEditDocumentFields,\n type WorkspaceMemberRole,\n} from '../../../files/permissions'\nimport type { FileTileDocument } from '../explorer/FileTiles'\nimport type { GridUser } from './cells'\nimport {\n CreatedByCellRenderer,\n DocumentNameCellRenderer,\n FolderCellRenderer,\n LabelsCellRenderer,\n RelatedDocsCellRenderer,\n SharedCellRenderer,\n StatusCellRenderer,\n type DocumentNameCellParams,\n type FolderCellParams,\n type LabelsCellParams,\n type RelatedDocsCellParams,\n type SharedCellParams,\n type StatusCellParams,\n} from './documentCellRenderers'\nimport { createTagColumn } from './tagColumn'\n\n/** A row of the documents table. */\nexport type GridDocument = FileTileDocument & {\n /** The email sender of a document imported from mail (\"Ada <ada@x.com>\"). */\n sender?: string | null\n}\n\ntype Doc = GridDocument\ntype Tag = TagResponse\n\n/**\n * What the columns read through the grid's `context` (row-independent, so the column definitions\n * stay put when they change).\n */\nexport interface DocumentGridContext {\n getDocuments?: () => GridDocument[]\n getRelatedDocs?: () => RelatedDocsMap<GridDocument>\n getFamilyMeta?: () => Map<string, { tier: number; count: number }>\n getWorkspaceUsers?: () => GridUser[]\n getCurrentUserId?: () => string | undefined\n getViewingDocumentId?: () => string | null\n getHostActions?: () => DocumentHostActions\n updateFolder?: (docId: string, folder: string | null) => void\n}\n\n// Stable filter params object (reused across all filter columns)\nconst FILTER_PARAMS = {\n buttons: ['reset', 'apply'] as const,\n closeOnApply: true,\n}\n\nexport interface CreateDocumentColumnsParams {\n handleToggleDocumentViewer: (docId: string) => void\n onStatusClick?: () => void\n /** Per-row document actions for the unified name column's \u22EF kebab. */\n onReviewDocument?: (docId: string) => void\n /** Start a new chat scoped to one document, opening it in the side viewer. */\n onDocumentChat?: (docId: string) => void\n onDownloadDocument?: (doc: Doc) => void\n onMoveDocument?: (docId: string) => void\n onDeleteDocument?: (docId: string) => void\n isMember: boolean\n /**\n * The viewer's role in the workspace (null: not a member, e.g. a public workspace's visitor).\n * Only an owner or a collaborator edits documents someone else created.\n */\n workspaceRole: WorkspaceMemberRole | null\n currentUserExtId?: string\n availableTags: Tag[]\n createDocTag: Pick<ReturnType<typeof useAssignDocTags>, 'mutateAsync'>\n updateDocTag: Pick<ReturnType<typeof useUpdateDocTag>, 'mutateAsync'>\n deleteDocTag: Pick<ReturnType<typeof useRemoveDocTags>, 'mutateAsync'>\n createTag: Pick<ReturnType<typeof useCreateTag>, 'mutateAsync'>\n /** Share a document with the workspace, or make it private. */\n onToggleShared: (docId: string, shared: boolean) => void\n /** How a tag write's outcome is told (the environment's notify). */\n notify: (message: string, kind: 'success' | 'error') => void\n}\n\nexport function createDocumentColumns({\n handleToggleDocumentViewer,\n onStatusClick,\n onReviewDocument,\n onDocumentChat,\n onDownloadDocument,\n onMoveDocument,\n onDeleteDocument,\n isMember,\n workspaceRole,\n currentUserExtId,\n availableTags,\n createDocTag,\n updateDocTag,\n deleteDocTag,\n createTag,\n onToggleShared,\n notify,\n}: CreateDocumentColumnsParams): ColDef<Doc>[] {\n // Owner/creator check \u2014 the sole gate for the privacy/visibility toggle.\n const isRowEditableByOwner = (params: { data?: Doc | null }): boolean =>\n canChangeVisibility(params.data, currentUserExtId)\n\n // Regular fields: see canEditDocumentFields (shared with the detail pane).\n const isRowEditableByMember = (params: { data?: Doc | null }): boolean =>\n canEditDocumentFields(params.data, currentUserExtId, workspaceRole)\n\n const checkboxTags = availableTags.filter(isLabelTag)\n\n const allColumns: ColDef<Doc>[] = []\n\n // Status column - shows status indicator (checkmark, error, progress bar)\n allColumns.push({\n colId: 'status',\n headerName: 'Status',\n field: 'status',\n // Wide enough for the full \"Status\" header (plus its sort indicator) to show\n // without truncating. suppressSizeToFit so it doesn't grow to fill space.\n width: 144,\n minWidth: 128,\n suppressSizeToFit: true,\n sortable: true,\n cellDataType: 'text',\n context: { icon: Paperclip },\n valueGetter: (params) => {\n if (!params.data) return null\n return params.data.status?.toLowerCase() ?? null\n },\n comparator: (\n a: string | null,\n b: string | null,\n nodeA: IRowNode<Doc>,\n nodeB: IRowNode<Doc>\n ) => {\n const STATUS_ORDER: Record<string, number> = {\n queued: 0,\n parsing: 1,\n encrypting: 2,\n indexing: 3,\n analysing: 4,\n completed: 5,\n 'low-content': 6,\n empty: 7,\n skipped: 8,\n failed: 9,\n }\n const rankA = a != null ? (STATUS_ORDER[a] ?? 10) : 10\n const rankB = b != null ? (STATUS_ORDER[b] ?? 10) : 10\n if (rankA !== rankB) return rankA - rankB\n // Secondary sort: within 'failed', order by pipeline stage\n if (a === 'failed' && b === 'failed') {\n const STAGE_ORDER: Record<string, number> = {\n parsing: 0,\n encrypting: 1,\n indexing: 2,\n analysing: 3,\n queued: 4,\n unknown: 5,\n }\n const stageA = nodeA.data?.failed_stage ?? null\n const stageB = nodeB.data?.failed_stage ?? null\n const stageRankA = stageA != null ? (STAGE_ORDER[stageA] ?? 6) : 7\n const stageRankB = stageB != null ? (STAGE_ORDER[stageB] ?? 6) : 7\n return stageRankA - stageRankB\n }\n return 0\n },\n cellRenderer: StatusCellRenderer,\n cellRendererParams: { onStatusClick } satisfies StatusCellParams,\n // Status is a single icon \u2014 center it horizontally (header + cell) rather\n // than left-aligning a lone glyph against the column edge. `cell-status`\n // trims the cell's vertical padding so the progress bar + label fit (and sit\n // near the top) even at the minimum row height.\n cellClass: 'cell-hcenter cell-status',\n headerClass: 'header-hcenter',\n })\n\n // (The per-row \"In Chat\" toggle column was removed \u2014 adding documents to the\n // current chat is now done via the bulk-actions toolbar after selecting rows.)\n\n // Document Name column\n // Unified Document column: entity badge (icon + title) opens the doc on click;\n // a hover \u22EF kebab carries the row actions (incl. Rename \u2014 no inline pencil).\n // Stays editable so the kebab's Rename can trigger the inline title editor;\n // edit is double-click / kebab only (not single-click, which opens).\n allColumns.push({\n colId: 'title',\n headerName: 'Title',\n // `initialFlex` (not `flex`): a stateful `flex` gets re-asserted every time\n // AG Grid re-processes the column definitions \u2014 which happens on many host\n // re-renders, including the one triggered by persisting the grid state\n // right after a manual resize \u2014 recomputing Title back to fill the leftover\n // space and snapping away the user's drag. With initialFlex the fill only\n // applies when the column is first created; after that a manual resize\n // sticks. The 160px floor lets the phone's Title + Status list fit 390px without sideways scroll.\n initialFlex: 3,\n minWidth: isPhoneViewport() ? 160 : 280,\n // Title is intentionally NOT pinned on mount: the default layout wants the\n // row-select checkbox as the first column with Title second. AG Grid always\n // renders pinned-left columns ahead of unpinned ones, so pinning Title (while\n // the selection column stays unpinned) pushed Title into the first slot,\n // ahead of the checkbox. Leaving it unpinned matches the built-in \"Default\n // view\" (which unpins everything) and lets the selection column sit first.\n // The \"Document view\" still pins the checkbox + Title left for users who want\n // the name frozen while scrolling the many data columns.\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n editable: isRowEditableByMember,\n cellEditor: 'agLargeTextCellEditor',\n cellEditorPopup: true,\n cellEditorParams: { rows: 5, cols: 50 },\n context: { icon: FileText },\n cellRenderer: DocumentNameCellRenderer,\n cellRendererParams: {\n canEdit: isRowEditableByMember,\n onOpenDocument: handleToggleDocumentViewer,\n onReviewDocument,\n onDocumentChat,\n onDownloadDocument,\n onMoveDocument,\n onDeleteDocument,\n } satisfies DocumentNameCellParams,\n valueGetter: (params) => getDocumentTitle(params.data, 'Untitled'),\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.title = params.newValue\n return true\n },\n // No AG Grid tooltip here \u2014 the DocumentEntity pill renders its own\n // AI-summary hover card (same one the explorer tiles use). A\n // tooltipValueGetter would stack a second, plain title tooltip on top.\n })\n\n // Document Type column (AI-generated, user-editable dropdown)\n // Options from DOCUMENT_TYPE_OPTIONS constant (synced with backend DocTagLLM.DEFAULT_METADATA_TAGS)\n allColumns.push({\n colId: 'doc_nature',\n headerName: 'Type',\n width: 120,\n minWidth: 100,\n sortable: true,\n filter: 'agTextColumnFilter',\n editable: isRowEditableByMember,\n singleClickEdit: true,\n cellEditor: 'agSelectCellEditor',\n cellEditorParams: {\n values: [...DOCUMENT_TYPE_OPTIONS],\n },\n context: { icon: Sparkles },\n valueGetter: (params) => getDocumentNature(params.data) || '',\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_nature = params.newValue || null\n return true\n },\n // Show dropdown indicator for editable cells (no custom renderer for performance)\n cellClass: (params) =>\n isRowEditableByMember(params) ? 'cell-select-editable' : 'cell-editable-readonly relative',\n })\n\n // Document Author column (AI-generated, user-editable)\n allColumns.push({\n colId: 'doc_author',\n headerName: 'Author',\n width: 150,\n minWidth: 100,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n editable: isRowEditableByMember,\n singleClickEdit: true,\n cellEditor: 'agLargeTextCellEditor',\n cellEditorPopup: true,\n cellEditorParams: { rows: 3, cols: 40 },\n context: { icon: User },\n valueGetter: (params) => getDocumentAuthor(params.data) || '',\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_author = params.newValue || null\n return true\n },\n tooltipValueGetter: (params) => getDocumentAuthor(params.data) || '',\n // cell-multiline: wrap long author lists to as many lines as the current\n // row height allows (same height-driven clamp as Abstract).\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative cell-multiline'\n : 'cell-editable-readonly relative cell-multiline',\n })\n\n // Document Abstract column (AI-generated, user-editable)\n allColumns.push({\n colId: 'doc_subject',\n headerName: 'Abstract',\n width: 300,\n minWidth: 200,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n editable: isRowEditableByMember,\n singleClickEdit: true,\n cellEditor: 'agLargeTextCellEditor',\n cellEditorPopup: true,\n cellEditorParams: { rows: 8, cols: 60 },\n context: { icon: FileText },\n // Edit against the raw markdown (so the large-text editor shows the real\n // source), but display a flattened plain-text preview in the cell and\n // tooltip \u2014 our AI summaries often contain markdown bullets/emphasis, and\n // rendering raw markers (\"* \u2026\", \"**\u2026**\") in a dense cell reads as noise.\n // markdownToPlainText is a cheap string transform run only on visible cells.\n valueGetter: (params) => getDocumentSubject(params.data) || '',\n valueFormatter: (params) => markdownToPlainText(params.value),\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_subject = params.newValue || null\n return true\n },\n tooltipValueGetter: (params) => markdownToPlainText(getDocumentSubject(params.data)),\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative cell-multiline'\n : 'cell-editable-readonly relative cell-multiline',\n })\n\n // Date column\n // Optimized: Using AG Grid's built-in editing + CSS-only hover icons (no React cellRenderer)\n allColumns.push({\n colId: 'doc_date',\n headerName: 'Date',\n width: 160,\n minWidth: 150, // Wider to fit an optional time (emails carry date + time)\n sortable: true,\n editable: isRowEditableByMember,\n singleClickEdit: true,\n context: { icon: Calendar },\n valueGetter: (params) => getDocumentDate(params.data),\n valueSetter: (params) => {\n if (!params.data) return false\n if (!params.data.doc_metadata) {\n params.data.doc_metadata = {}\n }\n params.data.doc_metadata.doc_date = params.newValue\n return true\n },\n valueFormatter: (params) => {\n if (!params.value) return '\u2014'\n return formatDocDate(params.value)\n },\n // Ensure text doesn't overflow - use cellStyle for overflow handling\n cellStyle: {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n },\n // Add Tailwind classes + CSS class for hover icon (pencil if editable, ban if not)\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative cell-tnum'\n : 'cell-editable-readonly relative cell-tnum',\n // Date filter with a start/end range (date-only comparison; ignores any time).\n filter: 'agDateColumnFilter',\n filterParams: {\n browserDatePicker: true,\n inRangeInclusive: true,\n // cellValue is the raw doc_date string (date or datetime); compare date-only.\n comparator: (filterDate: Date, cellValue: string | null) => {\n if (!cellValue) return -1\n const d = new Date(cellValue)\n if (Number.isNaN(d.getTime())) return -1\n const cellDay = new Date(d.getFullYear(), d.getMonth(), d.getDate())\n if (cellDay < filterDate) return -1\n if (cellDay > filterDate) return 1\n return 0\n },\n },\n // No valueParser - let user type freely without validation interrupting\n // Validation happens in onCellValueChanged after editing completes\n // No cellRenderer - AG Grid handles rendering natively with valueFormatter\n })\n\n // Pages column\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'n_pages',\n headerName: 'Pages',\n field: 'n_pages',\n width: 100,\n sortable: true,\n cellDataType: 'number',\n cellClass: 'cell-numeric',\n context: { icon: Hash },\n valueGetter: (params) => {\n return params.data?.n_pages || null\n },\n valueFormatter: (params) => {\n if (params.value === null || params.value === undefined) return '\u2014'\n return params.value.toLocaleString()\n },\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // Upload date column - just the date, sortable by date\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'created_at',\n headerName: 'Uploaded',\n field: 'created_at',\n width: 160,\n sortable: true,\n filter: 'agDateColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Upload },\n valueFormatter: (params) => {\n if (!params.value) return '\u2014'\n return formatFriendlyDate(params.value)\n },\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // Last modified column\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'updated_at',\n headerName: 'Last modified',\n field: 'updated_at',\n width: 160,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n filter: 'agDateColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Clock },\n valueFormatter: (params) => {\n if (!params.value) return '\u2014'\n return formatFriendlyDate(params.value)\n },\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // File name column\n // Optimized: Using native rendering - no cellRenderer needed for simple text\n allColumns.push({\n colId: 'file_name',\n headerName: 'File name',\n field: 'file_name',\n width: 200,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: File },\n // No cellRenderer - AG Grid handles text rendering natively\n })\n\n // Size column\n // Optimized: Using valueFormatter instead of React cellRenderer\n allColumns.push({\n colId: 'file_size',\n headerName: 'Size',\n field: 'file_size',\n width: 100,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n cellDataType: 'number',\n cellClass: 'cell-numeric',\n context: { icon: HardDrive },\n valueFormatter: (params) => formatFileSize(params.value),\n // No cellRenderer - valueFormatter handles display formatting\n })\n\n // File type column.\n //\n // Backend stores ``file_type`` as either a bare extension (``\"pdf\"``)\n // or a full MIME type (``\"application/pdf\"``) depending on which\n // upload path produced the row, so we never render the raw value.\n // ``valueGetter`` runs once per row to produce the friendly label \u2014\n // sort and the text filter then operate on that label, which is what\n // the user actually sees.\n allColumns.push({\n colId: 'file_type',\n headerName: 'File type',\n field: 'file_type',\n width: 120,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: FileType },\n valueGetter: (params) =>\n friendlyFileType(params.data?.file_type, params.data?.file_name, params.data?.folder),\n })\n\n // Folder column\n allColumns.push({\n colId: 'folder',\n headerName: 'Folder',\n field: 'folder',\n width: 180,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: FolderOpen },\n valueFormatter: (params) => formatFolderLabel(params.value),\n cellRenderer: FolderCellRenderer,\n cellRendererParams: { canEdit: isRowEditableByMember } satisfies FolderCellParams,\n cellClass: (params) =>\n isRowEditableByMember(params)\n ? 'cell-editable-member relative'\n : 'cell-editable-readonly relative',\n })\n\n // From column \u2014 email sender for connector-imported docs (e.g.\n // \"John Smith <john@x.com>\"). Plain text; null for non-email docs.\n allColumns.push({\n colId: 'sender',\n headerName: 'From',\n field: 'sender',\n width: 180,\n minWidth: 100,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Mail },\n valueGetter: (params) => params.data?.sender ?? '',\n tooltipValueGetter: (params) => params.data?.sender ?? '',\n // No cellRenderer - AG Grid handles text rendering natively\n })\n\n // Content Hash column\n allColumns.push({\n colId: 'content_hash',\n headerName: 'Fingerprint',\n field: 'content_hash',\n width: 200,\n sortable: true,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Fingerprint },\n cellStyle: { fontFamily: 'monospace' },\n valueFormatter: (params) => params.value || '',\n })\n\n // Related documents column \u2014 shows parent, children, duplicates, similar docs.\n //\n // Tiered sort key (string-compared by AG Grid; defaults to descending so\n // the first header click pulls the most-relevant tier to the top):\n //\n // {tier}|{paddedCount}|{groupId}|{rank}|{external_id}\n //\n // - tier (single digit, higher = top under desc):\n // 3 family has any duplicates\n // 2 family has any similar (no dupes)\n // 1 pure parent/child family (no dupes, no similar)\n // 0 no relationships at all\n // Family tier is computed once per groupId in Documents.tsx so every\n // member of a family shares the same prefix and stays clustered.\n // - paddedCount: aggregate count for the tier, zero-padded to 6 chars\n // so a lexical compare matches a numeric one.\n // - groupId: parent_ext_id for children, own external_id for parents\n // and lone docs, content_hash for standalone duplicate clusters.\n // - rank: 0 for parent/standalone, 1 for children \u2192 parent sorts above\n // its children within a family.\n // - external_id: stable tiebreaker.\n allColumns.push({\n colId: 'related',\n headerName: 'Related',\n width: 200,\n minWidth: 120,\n sortable: true,\n sortingOrder: ['desc', 'asc', null],\n context: { icon: Link2 },\n valueGetter: (params) => {\n if (!params.data) return ''\n const doc = params.data\n const context = params.context as DocumentGridContext | undefined\n const map = context?.getRelatedDocs?.()\n const familyMeta = context?.getFamilyMeta?.()\n const related = map?.get(doc.external_id)\n const isChild = !!doc.parent_ext_id\n const isParent = related?.children && related.children.length > 0\n\n let groupId: string\n let rank: number\n\n if (isChild) {\n // Child: group under parent, rank 1 so parent sorts first\n groupId = doc.parent_ext_id!\n rank = 1\n } else if (isParent) {\n // Parent: group under self, rank 0\n groupId = doc.external_id\n rank = 0\n } else if (doc.content_hash && related && related.duplicates.length > 0) {\n // Standalone duplicate: group by fingerprint\n groupId = doc.content_hash\n rank = 0\n } else {\n // No relationships: sort by own ID\n groupId = doc.external_id\n rank = 0\n }\n\n const meta = familyMeta?.get(groupId) ?? { tier: 0, count: 0 }\n const paddedCount = String(meta.count).padStart(6, '0')\n\n return `${meta.tier}|${paddedCount}|${groupId}|${rank}|${doc.external_id}`\n },\n cellRenderer: RelatedDocsCellRenderer,\n cellRendererParams: {\n onOpenDocument: handleToggleDocumentViewer,\n onDeleteDocument,\n } satisfies RelatedDocsCellParams,\n })\n\n // Shared column\n // Note: Keeping SharedCell for interactive toggle (complex UI)\n allColumns.push({\n colId: 'shared',\n headerName: 'Sharing',\n field: 'shared',\n width: 124,\n minWidth: 124,\n sortable: true,\n cellDataType: 'boolean',\n context: { icon: Share2 },\n valueGetter: (params) => {\n return params.data?.shared ?? false\n },\n cellRenderer: SharedCellRenderer,\n cellRendererParams: {\n canToggle: isRowEditableByOwner,\n onToggleShared,\n } satisfies SharedCellParams,\n })\n\n // Created by column - shows avatar icon (the members come through the grid's context)\n allColumns.push({\n colId: 'created_by',\n headerName: 'By',\n width: 60,\n sortable: true,\n context: { icon: User },\n valueGetter: (params) => {\n if (!params.data) return ''\n const users = (params.context as DocumentGridContext | undefined)?.getWorkspaceUsers?.()\n const creator = users?.find((u) => u.external_id === params.data!.created_by_ext_id)\n if (!creator) return ''\n const fullName = [creator.given_name, creator.family_name].filter(Boolean).join(' ')\n return fullName || creator.email || ''\n },\n cellRenderer: CreatedByCellRenderer,\n })\n\n // Labels column \u2014 shows applied checkbox/label tags as filled checkmarks\n allColumns.push({\n colId: 'all_tags',\n headerName: 'Labels',\n width: 300,\n // Never narrower than its own header (\"Labels\" + filter/menu icons) \u2014 the\n // title must not ellipsize, same floor as the Facts table's Labels column.\n minWidth: 132,\n sortable: false,\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Tags },\n valueGetter: (params) => {\n if (!params.data || !params.data.doctags) return ''\n // Only index label (and issue) names for filtering\n const tagNames = params.data.doctags\n .map((dt) => {\n const tag = availableTags.find((t) => t.external_id === dt.tag_ext_id)\n if (!tag || !isLabelTag(tag)) return ''\n return tag.name\n })\n .filter(Boolean)\n return tagNames.join(' ')\n },\n cellRenderer: LabelsCellRenderer,\n cellRendererParams: {\n labels: checkboxTags,\n createDocTag,\n deleteDocTag,\n createTag,\n isMember,\n } satisfies LabelsCellParams,\n // Add CSS class for hover icon (matches title field)\n cellClass: isMember ? 'cell-editable-member relative !pr-0' : 'cell-editable-readonly relative',\n })\n\n // DocID column\n // Optimized: Using valueFormatter for monospace font styling\n // Note: AG Grid doesn't support className in valueFormatter, so we'll use cellStyle instead\n allColumns.push({\n colId: 'doc_id',\n headerName: 'DocID',\n field: 'external_id',\n width: 200,\n sortable: true,\n // Visibility controlled by grid state, not column definition\n filter: 'agTextColumnFilter',\n filterParams: FILTER_PARAMS,\n context: { icon: Hash },\n cellStyle: { fontFamily: 'monospace' },\n // No cellRenderer - native rendering with cellStyle for monospace font\n })\n\n // A column per annotation (labels and issues are in the Labels column)\n const tagColumns = availableTags.filter(isAnnotationTag).map((tag) =>\n createTagColumn({\n tag,\n isMember,\n notify,\n createDocTag,\n updateDocTag,\n deleteDocTag,\n })\n )\n\n // Return ALL columns - AG Grid state controls visibility and order\n return [...allColumns.map(withEmptyDash), ...tagColumns]\n}\n\n/** Title is the most important field, so it gets a wide floor everywhere but a phone. */\nfunction isPhoneViewport(): boolean {\n return (\n typeof window !== 'undefined' && window.matchMedia?.('(max-width: 480px)')?.matches === true\n )\n}\n\n/** Columns whose empty values read as a muted em dash (never a blank cell or an error-like word). */\nconst EMPTY_DASH_COLUMNS: ReadonlySet<string> = new Set([\n 'doc_nature',\n 'doc_author',\n 'doc_subject',\n 'doc_date',\n 'n_pages',\n 'created_at',\n 'updated_at',\n 'file_name',\n 'file_type',\n 'sender',\n])\n\n/** The AI abstract step writes this literal when it finds nothing; to a reader it looks like an error. */\nconst NO_VALUE = /^\\s*(not found|n\\/a)\\.?\\s*$/i\n\nfunction isEmptyCell(value: unknown): boolean {\n return value === null || value === undefined || value === '' || NO_VALUE.test(String(value))\n}\n\n/**\n * Show an em dash, in the muted text colour, for empty values of the plain data columns. Formatting\n * only: the underlying value (and what the cell editors start from) is untouched.\n */\nfunction withEmptyDash(col: ColDef<Doc>): ColDef<Doc> {\n if (!col.colId || !EMPTY_DASH_COLUMNS.has(col.colId)) return col\n const { valueFormatter, cellClass } = col\n return {\n ...col,\n valueFormatter: (params) => {\n if (col.colId !== 'n_pages' && isEmptyCell(params.value)) return '\u2014'\n return typeof valueFormatter === 'function'\n ? valueFormatter(params)\n : String(params.value ?? '')\n },\n cellClass: (params) => {\n const base = typeof cellClass === 'function' ? cellClass(params) : cellClass\n const classes = Array.isArray(base) ? base : base ? [base] : []\n return isEmptyCell(params.value) ? [...classes, 'cell-empty'] : classes\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import {
|
|
4
4
|
Button,
|
|
5
|
-
Slider,
|
|
6
5
|
Select,
|
|
7
6
|
SelectContent,
|
|
8
7
|
SelectItem,
|
|
9
8
|
SelectTrigger,
|
|
10
9
|
SelectValue
|
|
11
10
|
} from "@arbidocs/react/ui";
|
|
12
|
-
import { ArrowDown, ArrowUp, Eye, EyeOff
|
|
11
|
+
import { ArrowDown, ArrowUp, Eye, EyeOff } from "lucide-react";
|
|
12
|
+
import { ZoomSlider } from "../../../components/ZoomSlider.js";
|
|
13
13
|
import { RowDensityControl } from "../../../files/grid/RowDensityControl.js";
|
|
14
14
|
import { TILE_DEFAULT, TILE_MAX, TILE_MIN } from "../explorer/ConnectedFilesExplorer.js";
|
|
15
15
|
import { ViewSelector } from "../views/ViewSelector.js";
|
|
@@ -127,32 +127,21 @@ function DocumentsFilterBarActions({
|
|
|
127
127
|
]
|
|
128
128
|
}
|
|
129
129
|
),
|
|
130
|
-
/* @__PURE__ */
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
value: [explorerTileSize],
|
|
146
|
-
min: TILE_MIN,
|
|
147
|
-
max: TILE_MAX,
|
|
148
|
-
step: 4,
|
|
149
|
-
onValueChange: ([v]) => onExplorerTileSizeChange(v),
|
|
150
|
-
"aria-label": "Tile size",
|
|
151
|
-
"data-testid": "explorer-zoom",
|
|
152
|
-
className: "w-20"
|
|
153
|
-
}
|
|
154
|
-
)
|
|
155
|
-
] })
|
|
130
|
+
/* @__PURE__ */ jsx(
|
|
131
|
+
ZoomSlider,
|
|
132
|
+
{
|
|
133
|
+
value: explorerTileSize,
|
|
134
|
+
min: TILE_MIN,
|
|
135
|
+
max: TILE_MAX,
|
|
136
|
+
step: 4,
|
|
137
|
+
zoomOutStep: 28,
|
|
138
|
+
onChange: onExplorerTileSizeChange,
|
|
139
|
+
label: "Tile size",
|
|
140
|
+
zoomOutLabel: "Smaller tiles",
|
|
141
|
+
testId: "explorer-zoom",
|
|
142
|
+
zoomOutTestId: "explorer-zoom-out"
|
|
143
|
+
}
|
|
144
|
+
)
|
|
156
145
|
] });
|
|
157
146
|
}
|
|
158
147
|
return null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/connection/files/page/DocumentsFilterBarActions.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * DocumentsFilterBarActions\n *\n * Right-hand action cluster rendered inside DocumentsFilterBar. Content\n * depends on the active Documents view:\n * - grid / navigator: saved-views selector, row density control, viewer toggle\n * - explorer: new-folder button, sort controls, tile-size zoom\n *\n * Kept out of Documents.tsx purely to shrink that file \u2014 this component\n * owns no state of its own, it's a pass-through view for page-level state.\n */\n\nimport {\n Button,\n
|
|
5
|
-
"mappings": ";AA8EQ,cAoBE,YApBF;AAlER;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * DocumentsFilterBarActions\n *\n * Right-hand action cluster rendered inside DocumentsFilterBar. Content\n * depends on the active Documents view:\n * - grid / navigator: saved-views selector, row density control, viewer toggle\n * - explorer: new-folder button, sort controls, tile-size zoom\n *\n * Kept out of Documents.tsx purely to shrink that file \u2014 this component\n * owns no state of its own, it's a pass-through view for page-level state.\n */\n\nimport {\n Button,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@arbidocs/react/ui'\nimport { ArrowDown, ArrowUp, Eye, EyeOff } from 'lucide-react'\nimport { ZoomSlider } from '../../../components/ZoomSlider'\nimport type { GridApi } from 'ag-grid-community'\nimport { RowDensityControl } from '../../../files/grid/RowDensityControl'\nimport type { ExplorerSort } from '../../../files/folders'\nimport { TILE_DEFAULT, TILE_MAX, TILE_MIN } from '../explorer/ConnectedFilesExplorer'\nimport type { GridDocument as Doc } from '../grid/documentColumns'\nimport { ViewSelector, type LoadableTableView } from '../views/ViewSelector'\n\ntype DocumentsViewMode = 'grid' | 'explorer' | 'navigator'\n\nexport interface DocumentsFilterBarActionsProps {\n isModal: boolean\n documentsViewMode: DocumentsViewMode\n getGridApi: () => GridApi<Doc> | null\n defaultVisibleColumns: string[]\n onApplyView: (columns: string[], gridApi?: GridApi<Doc>) => void\n onLoadView: (view: LoadableTableView, gridApi: GridApi<Doc>) => void\n explorerTileSize: number\n onExplorerTileSizeChange: (size: number) => void\n documentsRowHeight: number\n onDocumentsRowHeightChange: (height: number) => void\n currentDocument: Doc | null\n isDocumentViewerEnabled: boolean\n onToggleDocumentViewer: (docId: string) => void\n explorerSort: ExplorerSort\n onExplorerSortChange: (sort: ExplorerSort) => void\n explorerSortReversed: boolean\n onExplorerSortReversedChange: (reversed: boolean) => void\n /** Changes whenever the grid's saved state does (the saved-views menu recomputes). */\n gridStateVersion: unknown\n}\n\nexport function DocumentsFilterBarActions({\n isModal,\n documentsViewMode,\n getGridApi,\n defaultVisibleColumns,\n onApplyView,\n onLoadView,\n explorerTileSize,\n onExplorerTileSizeChange,\n documentsRowHeight,\n onDocumentsRowHeightChange,\n currentDocument,\n isDocumentViewerEnabled,\n onToggleDocumentViewer,\n explorerSort,\n onExplorerSortChange,\n explorerSortReversed,\n onExplorerSortReversedChange,\n gridStateVersion,\n}: DocumentsFilterBarActionsProps) {\n if (isModal) return null\n\n if (documentsViewMode === 'grid' || documentsViewMode === 'navigator') {\n return (\n <div className=\"flex items-center gap-2\">\n <ViewSelector\n getGridApi={getGridApi}\n defaultColumns={defaultVisibleColumns}\n onApplyView={onApplyView}\n onLoadView={onLoadView}\n currentTileSize={explorerTileSize}\n currentRowHeight={documentsRowHeight}\n defaultTileSize={TILE_DEFAULT}\n stateVersion={gridStateVersion}\n />\n {documentsViewMode === 'grid' && (\n // The phone list is a fixed two-line layout, so row density only applies from sm up.\n <div className=\"hidden sm:block\">\n <RowDensityControl\n rowHeight={documentsRowHeight}\n onRowHeightChange={onDocumentsRowHeightChange}\n />\n </div>\n )}\n {documentsViewMode === 'navigator' && currentDocument && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 px-2 gap-1.5\"\n onClick={() => onToggleDocumentViewer(currentDocument.external_id)}\n data-testid={`filter-bar-${isDocumentViewerEnabled ? 'close' : 'open'}-viewer-button`}\n >\n {isDocumentViewerEnabled ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n <span className=\"text-sm\">{isDocumentViewerEnabled ? 'Hide' : 'View'}</span>\n </Button>\n )}\n </div>\n )\n }\n\n if (documentsViewMode === 'explorer') {\n return (\n <div className=\"flex items-center gap-1.5\">\n <Select\n value={explorerSort}\n onValueChange={(v) => {\n onExplorerSortChange(v as ExplorerSort)\n onExplorerSortReversedChange(false)\n }}\n >\n <SelectTrigger\n className=\"h-7 w-32 whitespace-nowrap text-sm\"\n aria-label=\"Sort by\"\n data-testid=\"explorer-sort\"\n >\n <span className=\"!flex min-w-0 flex-nowrap items-center gap-1.5 whitespace-nowrap\">\n {/* Direction toggle lives INSIDE the trigger, on the left. Its own\n pointer handling stops the select from opening when you flip\n the direction. */}\n <span\n role=\"button\"\n tabIndex={0}\n onPointerDown={(e) => e.stopPropagation()}\n onClick={(e) => {\n e.stopPropagation()\n onExplorerSortReversedChange(!explorerSortReversed)\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n e.stopPropagation()\n onExplorerSortReversedChange(!explorerSortReversed)\n }\n }}\n aria-label=\"Reverse sort direction\"\n title=\"Reverse sort direction\"\n data-testid=\"explorer-sort-direction\"\n className=\"flex shrink-0 items-center text-muted-foreground hover:text-foreground pointer-coarse:-m-3.5 pointer-coarse:p-3.5\"\n >\n {explorerSortReversed ? (\n <ArrowUp className=\"h-3.5 w-3.5\" />\n ) : (\n <ArrowDown className=\"h-3.5 w-3.5\" />\n )}\n </span>\n <SelectValue placeholder=\"Sort\" />\n </span>\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"name\">Name</SelectItem>\n <SelectItem value=\"date\">Date</SelectItem>\n <SelectItem value=\"size\">Size</SelectItem>\n </SelectContent>\n </Select>\n <ZoomSlider\n value={explorerTileSize}\n min={TILE_MIN}\n max={TILE_MAX}\n step={4}\n zoomOutStep={28}\n onChange={onExplorerTileSizeChange}\n label=\"Tile size\"\n zoomOutLabel=\"Smaller tiles\"\n testId=\"explorer-zoom\"\n zoomOutTestId=\"explorer-zoom-out\"\n />\n </div>\n )\n }\n\n return null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -30,7 +30,7 @@ function useWorkspaceMailDocuments() {
|
|
|
30
30
|
const files = workspaceDocuments.filter((doc) => Boolean(doc.file_name));
|
|
31
31
|
return {
|
|
32
32
|
documents: files.map((doc) => {
|
|
33
|
-
const Icon = getFileTypeIcon(doc.file_name, { mime: doc.file_type });
|
|
33
|
+
const Icon = getFileTypeIcon(doc.file_name, { mime: doc.file_type, folder: doc.folder });
|
|
34
34
|
return { id: doc.external_id, title: getDocumentTitle(doc), icon: /* @__PURE__ */ jsx(Icon, { size: 14 }) };
|
|
35
35
|
}),
|
|
36
36
|
toAttachment: async (id, maxBytes) => {
|