@marimo-team/frontend 0.16.4 → 0.16.5
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/assets/{CellStatus-CEVFBnyt.js → CellStatus-BJRDATxe.js} +1 -1
- package/dist/assets/{ConnectedDataExplorerComponent-5izWKQVQ.js → ConnectedDataExplorerComponent-Cs4pQOKx.js} +1 -1
- package/dist/assets/{ImperativeModal-DujtmdOO.js → ImperativeModal-BG5LTpV0.js} +1 -1
- package/dist/assets/{JsonOutput-E2xVojk5.js → JsonOutput-BID8Oos7.js} +1 -1
- package/dist/assets/{LazyAnyLanguageCodeMirror-DHH4zj72.js → LazyAnyLanguageCodeMirror-RkzkO2YV.js} +2 -2
- package/dist/assets/MarimoErrorOutput-Lft73Wnl.js +6 -0
- package/dist/assets/{RenderHTML-BCi_V67U.js → RenderHTML-BoDLdBq-.js} +1 -1
- package/dist/assets/{VisuallyHidden-DvpnK2wO.js → VisuallyHidden-BiHw-PIc.js} +1 -1
- package/dist/assets/{accordion-C3CAEPwC.js → accordion-A41ffd5P.js} +1 -1
- package/dist/assets/{activity-BCW0BU81.js → activity-BhLNCNHF.js} +1 -1
- package/dist/assets/add-cell-with-ai-CxM_YKzf.js +36 -0
- package/dist/assets/{add-database-form-DSnHGqMe.js → add-database-form-Br1fMkMI.js} +1 -1
- package/dist/assets/{add-missing-import-Cwedhjm5.js → add-missing-import-CfRgNApn.js} +1 -1
- package/dist/assets/agent-panel-7ocujO8C.js +287 -0
- package/dist/assets/ai-model-dropdown-DSUVFIso.js +2 -0
- package/dist/assets/{alert-dialog-M1dUQe7C.js → alert-dialog-BO8sf-73.js} +1 -1
- package/dist/assets/{ansi_up-ZmFuCItK.js → ansi_up-D_b0GS7N.js} +1 -1
- package/dist/assets/{any-language-editor-BqGBgxZE.js → any-language-editor-edee1A1P.js} +1 -1
- package/dist/assets/app-config-button-Bg_CEfls.js +1 -0
- package/dist/assets/{architecture-O4VJ6CD3-CbkBEQri.js → architecture-O4VJ6CD3-CIYFBxkI.js} +1 -1
- package/dist/assets/{architectureDiagram-W76B3OCA-di95lJcF.js → architectureDiagram-W76B3OCA-CXqAkVTy.js} +1 -1
- package/dist/assets/{arrow-left-DQ-94PlS.js → arrow-left-D97p491f.js} +1 -1
- package/dist/assets/{between-horizontal-start-CotWLlFt.js → between-horizontal-start-DWTOsiF_.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-ClcJSQFf.js → blockDiagram-QIGZ2CNN-DhYrUig_.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-Cq2vxSdy.js → c4Diagram-FPNF74CW-Bj1S_Fyy.js} +1 -1
- package/dist/assets/{cell-actions-C5S4W3g_.js → cell-actions-hNx4EMmZ.js} +1 -1
- package/dist/assets/{cell-editor-X6EY7GQl.js → cell-editor-JimG_bBz.js} +13 -13
- package/dist/assets/cell-link-_kF38gGF.js +1 -0
- package/dist/assets/{cells-B4cnsYe_.js → cells-Dd1FatlG.js} +54 -54
- package/dist/assets/channel-Bil_pUlM.js +1 -0
- package/dist/assets/{chart-no-axes-column-DrG7h8mS.js → chart-no-axes-column-DmR44Tbq.js} +1 -1
- package/dist/assets/{chat-components-DXkntpg4.js → chat-components-OoNU4tLf.js} +3 -3
- package/dist/assets/chat-panel-DatwRFif.js +3 -0
- package/dist/assets/check-C5PVLNkJ.js +1 -0
- package/dist/assets/{chevron-right-Caf5yL5B.js → chevron-right-BDEhimQq.js} +1 -1
- package/dist/assets/{chunk-3AY6CYHV-BFFUJATX.js → chunk-3AY6CYHV-CBq2x1Nc.js} +1 -1
- package/dist/assets/{chunk-4KMFLZZN-D8J8fzqf.js → chunk-4KMFLZZN-DEMg9QYp.js} +1 -1
- package/dist/assets/{chunk-6OXUPJBA-Clo7-gS4.js → chunk-6OXUPJBA-CjFdZBrY.js} +2 -2
- package/dist/assets/{chunk-ABZYJK2D-DjRcbxmx.js → chunk-ABZYJK2D-eZsthrBr.js} +1 -1
- package/dist/assets/{chunk-BN7GFLIU-DvomLhVN.js → chunk-BN7GFLIU-ez-vZ7uD.js} +1 -1
- package/dist/assets/{chunk-CXMOBAN2-GhUPxuLT.js → chunk-CXMOBAN2-DxbPW6zT.js} +1 -1
- package/dist/assets/{chunk-EXTU4WIE-97Zvkznr.js → chunk-EXTU4WIE-C8Y_P6y8.js} +1 -1
- package/dist/assets/{chunk-JA3XYJ7Z-Mvfz9vG6.js → chunk-JA3XYJ7Z-pR89xWsn.js} +1 -1
- package/dist/assets/{chunk-JEIROHC2-Cp1tR_z8.js → chunk-JEIROHC2-2-ucCTVJ.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-BbFs0Y5e.js → chunk-K7UQS3LO-Bz3bjON2.js} +1 -1
- package/dist/assets/{chunk-KMC2YHZD-Buiqyl2g.js → chunk-KMC2YHZD-BvMr39QE.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-dhs223oU.js → chunk-QN33PNHL-DgF0LOHR.js} +1 -1
- package/dist/assets/{chunk-QYVHNE3D-DA_jYaIp.js → chunk-QYVHNE3D-BxN3DJBX.js} +1 -1
- package/dist/assets/{chunk-S3R3BYOJ-DO68jEIo.js → chunk-S3R3BYOJ-Dy72CLbv.js} +1 -1
- package/dist/assets/{chunk-T44TD3VJ-Ww2OhwR5.js → chunk-T44TD3VJ-BfMjD4hS.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-j2EljfwG.js → chunk-TVAH2DTR-CKnRAcjo.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-DYFKU4Pb.js → chunk-TZMSLE5B-DdgcuCwZ.js} +1 -1
- package/dist/assets/{chunk-WFRQ32O7-k2LaZwie.js → chunk-WFRQ32O7-CHVQx4E8.js} +1 -1
- package/dist/assets/{chunk-WFWHJNB7-h5yM_3qQ.js → chunk-WFWHJNB7-B095GDsj.js} +1 -1
- package/dist/assets/{chunk-XRWGC2XP-C9Mh6qts.js → chunk-XRWGC2XP-C9u0mhR4.js} +1 -1
- package/dist/assets/{circle-play-Cktn64O2.js → circle-play-BnvyuDgL.js} +1 -1
- package/dist/assets/{circle-plus-CR5IX63e.js → circle-plus-CfdbDkkn.js} +1 -1
- package/dist/assets/{circle-x-t3DIkXqJ.js → circle-x-BsVcxKkV.js} +1 -1
- package/dist/assets/classDiagram-KNZD7YFC-CjqRV-TB.js +1 -0
- package/dist/assets/classDiagram-v2-RKCZMP56-CGekJfCg.js +1 -0
- package/dist/assets/client-RNr6mM1Y.js +2 -0
- package/dist/assets/{clipboard-paste-CCXUHJEo.js → clipboard-paste-CYFMW3x7.js} +1 -1
- package/dist/assets/column-preview-2H8pwalb.js +2 -0
- package/dist/assets/{columns-BBxos2iF.js → columns-qXe5bccO.js} +7 -7
- package/dist/assets/{command-CMralWVx.js → command-BZVf1cJP.js} +1 -1
- package/dist/assets/command-palette-CYMxp9xF.js +1 -0
- package/dist/assets/{common-CGhyb0HV.js → common-DW3bNKWY.js} +1 -1
- package/dist/assets/{config-DiCy6eC0.js → config-DXGmIv9f.js} +1 -1
- package/dist/assets/{copy-DAVB02c8.js → copy-6mpL4BeI.js} +1 -1
- package/dist/assets/{copy-icon-GGPHJWJ0.js → copy-icon-6ICckC-p.js} +1 -1
- package/dist/assets/{dagre-5GWH7T2D-B1wEBSrx.js → dagre-5GWH7T2D-hVCok2au.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-Drp4I0tg.js → data-grid-overlay-editor-BwcAr1JM.js} +1 -1
- package/dist/assets/datasources-panel-BvrtAadm.js +1 -0
- package/dist/assets/{dates-grtSI02N.js → dates-Au76svwW.js} +1 -1
- package/dist/assets/dependency-graph-panel-F9AD_whb.js +4 -0
- package/dist/assets/{diagram-N5W7TBWH-D0MGIq61.js → diagram-N5W7TBWH-C26XpepA.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-DU6geLeA.js → diagram-QEK2KX5R-yrTR8I_L.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-BNhY4Z1-.js → diagram-S2PKOQOG-BnrvSrEb.js} +1 -1
- package/dist/assets/{dialog-B7icy1Vb.js → dialog-CR68_CUl.js} +1 -1
- package/dist/assets/{dist-BNjtn4W8.js → dist--01dzFeG.js} +1 -1
- package/dist/assets/{dist-BagyUivg.js → dist--UHY1FN-.js} +1 -1
- package/dist/assets/{dist-5Gm6w_15.js → dist-6vTAXnMq.js} +1 -1
- package/dist/assets/{dist-DTazGMur.js → dist-B6CCfKkp.js} +1 -1
- package/dist/assets/dist-BAqgWgpM.js +1 -0
- package/dist/assets/{dist-BaApG_tl.js → dist-BUe_o-3o.js} +1 -1
- package/dist/assets/{dist-BpAb8rGb.js → dist-BnTbfmCK.js} +1 -1
- package/dist/assets/dist-C-4GTx-T.js +1 -0
- package/dist/assets/{dist-C0ek66tJ.js → dist-C1lnVyyK.js} +1 -1
- package/dist/assets/{dist-DGiVfc7V.js → dist-CbsJnssA.js} +1 -1
- package/dist/assets/{dist-DV-8bxFo.js → dist-CjoeBoZ9.js} +1 -1
- package/dist/assets/{dist-D5QvSsL_.js → dist-CsC8ZokE.js} +1 -1
- package/dist/assets/{dist-C69eWtaQ.js → dist-CyqTsfyg.js} +1 -1
- package/dist/assets/dist-D-ZYdf69.js +1 -0
- package/dist/assets/dist-D3B_GqVR.js +1 -0
- package/dist/assets/{dist-BME02X12.js → dist-DFJwMM7Z.js} +1 -1
- package/dist/assets/dist-Db9UVaw9.js +1 -0
- package/dist/assets/{dist-BPr57Wxb.js → dist-DhXqYYeD.js} +1 -1
- package/dist/assets/{dist-CL0hPMY6.js → dist-Dm8m1boP.js} +1 -1
- package/dist/assets/{dist-B0vg88Aq.js → dist-DvDyxv8b.js} +1 -1
- package/dist/assets/{dist-Bzn1Zd0x.js → dist-DzUKODTF.js} +1 -1
- package/dist/assets/dist-LmEq3o4w.js +1 -0
- package/dist/assets/dist-Z_cK0cSh.js +1 -0
- package/dist/assets/dist-biP83Yvc.js +1 -0
- package/dist/assets/dist-dJ4FqqTe.js +1 -0
- package/dist/assets/{documentation-panel-D4iq1tSm.js → documentation-panel-DYKAf6Sg.js} +1 -1
- package/dist/assets/{dom-4KyFHEbl.js → dom-CT3dAMQW.js} +1 -1
- package/dist/assets/{download-C4Fyu6kU.js → download-B4_BX7gi.js} +1 -1
- package/dist/assets/{download-qt61TbgC.js → download-BB5Iexmn.js} +1 -1
- package/dist/assets/{dropdown-menu-Bp1vhqcS.js → dropdown-menu-CJDB1PNI.js} +1 -1
- package/dist/assets/edit-page-BK3Irdme.js +12 -0
- package/dist/assets/{ellipsis-DVXWk8Lc.js → ellipsis-CJtiw1k3.js} +1 -1
- package/dist/assets/{ellipsis-vertical-DfpheMuY.js → ellipsis-vertical-DK--y082.js} +1 -1
- package/dist/assets/{en-US-B2g9dciI.js → en-US-CjWuOpsV.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-DxxWZrYD.js → erDiagram-AWTI2OKA-9EqwLrlG.js} +1 -1
- package/dist/assets/{error-banner-ARu6PiHL.js → error-banner-BGjnZePp.js} +1 -1
- package/dist/assets/error-panel-CrkbkIF_.js +1 -0
- package/dist/assets/{es-C0Ih1AxE.js → es-C-CWIA-E.js} +1 -1
- package/dist/assets/{esm-BR7TuyMc.js → esm-7XxuulnL.js} +1 -1
- package/dist/assets/{esm-Cb-iIF_w.js → esm-B39og2OG.js} +1 -1
- package/dist/assets/{esm-BIF8NHm8.js → esm-BBn_y9Ew.js} +1 -1
- package/dist/assets/esm-DjUQOOJ2.js +1 -0
- package/dist/assets/{eye-off-BEVibdMQ.js → eye-off-9UMe_Y7D.js} +1 -1
- package/dist/assets/field-D6g5A_wf.js +1 -0
- package/dist/assets/{file-DqkkCGhs.js → file-BENStGHx.js} +1 -1
- package/dist/assets/file-explorer-panel-Cgv3WjVh.js +1 -0
- package/dist/assets/{file-plus-2-BCmZgbYs.js → file-plus-2-CloHhbsF.js} +1 -1
- package/dist/assets/{file-text-DNmaotaP.js → file-text-Lr1kJd4E.js} +1 -1
- package/dist/assets/{file-video-camera-C5lALvNf.js → file-video-camera-CfnyBQQe.js} +1 -1
- package/dist/assets/filename-B5Yo1bOu.js +1 -0
- package/dist/assets/{floating-outline-Cjas_exC.js → floating-outline-DZnSnZfg.js} +1 -1
- package/dist/assets/{flowDiagram-PVAE7QVJ-DlTZtqcN.js → flowDiagram-PVAE7QVJ-iOj6Qgu-.js} +1 -1
- package/dist/assets/{focus-OWoLlKnm.js → focus-Bnk25hTp.js} +1 -1
- package/dist/assets/{form-xOqp67zT.js → form-BGZvwlog.js} +1 -1
- package/dist/assets/{form--nX5W3gQ.js → form-DyKYT1WR.js} +1 -1
- package/dist/assets/{formats-C8bbggqj.js → formats-CWdWXhfT.js} +1 -1
- package/dist/assets/{fullscreen-BFmvQx5m.js → fullscreen-DTPr3iBY.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-BEPmawB5.js → ganttDiagram-OWAHRB6G-BWbXeAXa.js} +1 -1
- package/dist/assets/{gitGraph-ZV4HHKMB-DsmmnKI3.js → gitGraph-ZV4HHKMB-BpeeuO4L.js} +1 -1
- package/dist/assets/{gitGraphDiagram-NY62KEGX-DfTKmX9v.js → gitGraphDiagram-NY62KEGX-BX3O-mzY.js} +1 -1
- package/dist/assets/{glide-data-editor-CzDe-oK3.js → glide-data-editor-C45ArX7n.js} +4 -4
- package/dist/assets/globals-BFoVgbHf.js +1 -0
- package/dist/assets/{globe-CgG1jfYF.js → globe-CPrVx8HM.js} +1 -1
- package/dist/assets/home-page-DhT6cm6c.js +4 -0
- package/dist/assets/{image-DXGqie4b.js → image-DTv0Ic6H.js} +1 -1
- package/dist/assets/{index-DtggTI4O.js → index-29P5xX8u.js} +11 -11
- package/dist/assets/index-Optxbl37.css +2 -0
- package/dist/assets/{info-63CPKGFF-BVRAJzgS.js → info-63CPKGFF-Czr08O9A.js} +1 -1
- package/dist/assets/{infoDiagram-STP46IZ2-CcEqfhrj.js → infoDiagram-STP46IZ2-C1JX9JfB.js} +1 -1
- package/dist/assets/input-C1RzjWSK.js +7 -0
- package/dist/assets/{isValid-gOtpcPxn.js → isValid-o3nZVu8e.js} +1 -1
- package/dist/assets/{journeyDiagram-BIP6EPQ6-CfxDuLls.js → journeyDiagram-BIP6EPQ6-CC2JvTQD.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-BwopERfW.js → kanban-definition-6OIFK2YF-3qAhCi66.js} +1 -1
- package/dist/assets/{key-BuxNhFKW.js → key-D4QiH_7H.js} +1 -1
- package/dist/assets/{kiosk-mode--OX2RHZj.js → kiosk-mode-Dy2WnuWt.js} +1 -1
- package/dist/assets/{label-COeaBwl_.js → label-BEUjZsdo.js} +1 -1
- package/dist/assets/{layout-CKoMTVJt.js → layout-C6K0XXFK.js} +3 -3
- package/dist/assets/{linear-BI0LBATm.js → linear-nWRf49aw.js} +1 -1
- package/dist/assets/{link-DSY8ADga.js → link-CDOxp9sn.js} +1 -1
- package/dist/assets/links-D-L0rzz9.js +1 -0
- package/dist/assets/{list-filter-D2Wx3thV.js → list-filter-CRC72QPW.js} +1 -1
- package/dist/assets/{loader-CPDA0quD.js → loader-CgbiPC_T.js} +1 -1
- package/dist/assets/logs-panel-BB-6orqg.js +1 -0
- package/dist/assets/{maps-CxCIYhRT.js → maps-DaQbs_UR.js} +1 -1
- package/dist/assets/{menu-items-COILZQ4q.js → menu-items-Bo6Dyd_Q.js} +1 -1
- package/dist/assets/{mermaid-oqJ6vLFm.js → mermaid-Bqzxmx0C.js} +1 -1
- package/dist/assets/{mermaid-parser.core-8414a7OP.js → mermaid-parser.core-CwRCqiGJ.js} +2 -2
- package/dist/assets/{mermaid.core-CKfX2q8j.js → mermaid.core-C4o4vdkw.js} +3 -3
- package/dist/assets/mermaid.core-DjncFP_O.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-nadsjaMC.js → mindmap-definition-Q6HEUPPD-pLcSm-bI.js} +1 -1
- package/dist/assets/{mode-CBh2Ag_Y.js → mode-DQPKc-Hp.js} +1 -1
- package/dist/assets/{name-cell-input-CAG50xh2.js → name-cell-input-DQd65hJw.js} +1 -1
- package/dist/assets/{number-overlay-editor-CbWBjwI1.js → number-overlay-editor-Ce_FEpnn.js} +1 -1
- package/dist/assets/once-8ZDiGGtA.js +1 -0
- package/dist/assets/outline-panel-BJDiYH61.js +1 -0
- package/dist/assets/packages-panel-D_VswrEd.js +1 -0
- package/dist/assets/{packet-HUATNLJX-BJ_b_gYi.js → packet-HUATNLJX-C5NsAS_7.js} +1 -1
- package/dist/assets/{pie-WTHONI2E-CS2JfH5S.js → pie-WTHONI2E-BCNGQ0_9.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-DP_lAtPz.js → pieDiagram-ADFJNKIX-CUCBn1VN.js} +1 -1
- package/dist/assets/plug-DrNpofTj.js +1 -0
- package/dist/assets/{plus-C1zexBxS.js → plus-d2HNOuZI.js} +1 -1
- package/dist/assets/{popover-CLp_lH16.js → popover-DW0D4l0O.js} +1 -1
- package/dist/assets/{precisionRound-CR2cxaaR.js → precisionRound-TxjBk8nN.js} +1 -1
- package/dist/assets/{quadrantDiagram-LMRXKWRM-gzT_-w3S.js → quadrantDiagram-LMRXKWRM-C6DXTSnZ.js} +1 -1
- package/dist/assets/{radar-NJJJXTRR-ChMDxgqR.js → radar-NJJJXTRR-Cck-wBOB.js} +1 -1
- package/dist/assets/{react-plotly-DUuIpNDT.js → react-plotly-x7-8ig7L.js} +1 -1
- package/dist/assets/{readonly-python-code-DMLMHG1v.js → readonly-python-code-Cb7Ak_Dy.js} +1 -1
- package/dist/assets/{refresh-ccw-lUiAEOAx.js → refresh-ccw-CCJeTTJO.js} +1 -1
- package/dist/assets/{refresh-cw-CSv3xyYY.js → refresh-cw-B_tmnHav.js} +1 -1
- package/dist/assets/{renderShortcut-DMYtt-ju.js → renderShortcut-C9_NT6sD.js} +1 -1
- package/dist/assets/{request-registry-4Bq310sk.js → request-registry-D4PD0fDJ.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-aavD0qQF.js → requirementDiagram-4UW4RH46-Bj7w3axz.js} +1 -1
- package/dist/assets/run-page-D9jntYU0.js +1 -0
- package/dist/assets/{runs-CItfCHkl.js → runs-BWcKkv9g.js} +1 -1
- package/dist/assets/{sankeyDiagram-GR3RE2ED-r95m_h3N.js → sankeyDiagram-GR3RE2ED-DCmlCkUu.js} +1 -1
- package/dist/assets/{save-Bg0tsaXV.js → save-CVcbYdvl.js} +1 -1
- package/dist/assets/scratchpad-panel-BUGlPLwQ.js +1 -0
- package/dist/assets/{scroll-text-SAt1GCBr.js → scroll-text-CN-2fr92.js} +1 -1
- package/dist/assets/secrets-panel-DGPyMcTb.js +1 -0
- package/dist/assets/{select-CMG6DC3j.js → select-DKRTzlUU.js} +1 -1
- package/dist/assets/{send-ePQN2mpH.js → send-DRRBOpzT.js} +1 -1
- package/dist/assets/{sequenceDiagram-C3RYC4MD-C4GqHIgf.js → sequenceDiagram-C3RYC4MD-CtIOF8jj.js} +1 -1
- package/dist/assets/{settings-TIv8aSog.js → settings-6ySBJQ7Y.js} +1 -1
- package/dist/assets/{share-CUbi0XlA.js → share-Dcl7D_tA.js} +1 -1
- package/dist/assets/snippets-panel-CKi40HiX.js +1 -0
- package/dist/assets/{spinner-CxlO4-GJ.js → spinner-BhnfQOEl.js} +1 -1
- package/dist/assets/{square-uM1ci7iL.js → square-DKPXnMmD.js} +1 -1
- package/dist/assets/{square-function-OflPQrBg.js → square-function-DBJINsmk.js} +1 -1
- package/dist/assets/{square-terminal-DZAwMMdQ.js → square-terminal-DoFRZ-M6.js} +1 -1
- package/dist/assets/{src-BOK-SWX4.js → src-KuQao6GK.js} +1 -1
- package/dist/assets/state-B37sZn4X.js +1 -0
- package/dist/assets/{state-COfuW2QS.js → state-CEmS5WFQ.js} +1 -1
- package/dist/assets/state-jvUYiWCG.js +1 -0
- package/dist/assets/{stateDiagram-KXAO66HF-CdN43FzO.js → stateDiagram-KXAO66HF-DwZscOce.js} +1 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-D5XUGcJP.js +1 -0
- package/dist/assets/stex-C7nwqmPk.js +1 -0
- package/dist/assets/storage-CaQ7kwuv.js +1 -0
- package/dist/assets/{switch-BKaPFRvh.js → switch-B5bMMWJn.js} +1 -1
- package/dist/assets/{tabs-C8HicIPZ.js → tabs-8ThyQfYh.js} +1 -1
- package/dist/assets/{terminal-Cnm8ANjQ.js → terminal-CPdYItDn.js} +1 -1
- package/dist/assets/{text-search-DpMeajoz.js → text-search-iEvFn29l.js} +1 -1
- package/dist/assets/{textarea-DhU2DWSB.js → textarea-B-_OthMe.js} +1 -1
- package/dist/assets/{time-Dzg4b75Q.js → time-BkIHCvH2.js} +1 -1
- package/dist/assets/{timeline-definition-XQNQX7LJ-D48ppGT8.js → timeline-definition-XQNQX7LJ-BGsZ09p6.js} +1 -1
- package/dist/assets/{toDate-BartytS4.js → toDate-Daj1hQSF.js} +1 -1
- package/dist/assets/{toggle-BLLoLiay.js → toggle-BpFqu8FB.js} +1 -1
- package/dist/assets/{tooltip-BjoMzmCN.js → tooltip-ULHbIsj9.js} +1 -1
- package/dist/assets/tracing-UKZUjbDB.js +2 -0
- package/dist/assets/tracing-panel-CuDItRLt.js +2 -0
- package/dist/assets/{trash-2-GOPu47oc.js → trash-2-3UJSaMKF.js} +1 -1
- package/dist/assets/{trash-BpVsWH8l.js → trash-CYX7fe5Y.js} +1 -1
- package/dist/assets/{tree-qyAlDlFy.js → tree-3z9r1N_5.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-B4o24kyC.js → treemap-75Q7IDZK-MX1Hmq0m.js} +1 -1
- package/dist/assets/{type-C9leWRlU.js → type-kF6pOJbH.js} +1 -1
- package/dist/assets/{types-BBD3GQ0S.js → types-DQDL7dro.js} +1 -1
- package/dist/assets/{types-DEwRoAG0.js → types-DyTIgBnH.js} +1 -1
- package/dist/assets/{useAddCell-DJhNA_O5.js → useAddCell-Dq3HqYz1.js} +1 -1
- package/dist/assets/{useAsyncData-BEqqunls.js → useAsyncData-D9GA9BWg.js} +1 -1
- package/dist/assets/{useBoolean-DnggoYme.js → useBoolean-CSR3XjhE.js} +1 -1
- package/dist/assets/{useCellActionButton-B_a4Sv2X.js → useCellActionButton-BAG0Vvnt.js} +1 -1
- package/dist/assets/{useDateFormatter-DjmrLzxH.js → useDateFormatter-DrFLqO1D.js} +1 -1
- package/dist/assets/{useDebounce-9_rqRiHk.js → useDebounce-_ztZiL0I.js} +1 -1
- package/dist/assets/{useDeepCompareMemoize-DIhr42Iz.js → useDeepCompareMemoize-BsZY8i2r.js} +1 -1
- package/dist/assets/{useDeleteCell-DVNOLjwN.js → useDeleteCell-CJaipocw.js} +1 -1
- package/dist/assets/useHotkey-DkiyGPLs.js +1 -0
- package/dist/assets/{useInstallPackage-CTHO3tj3.js → useInstallPackage-DoKAq17E.js} +1 -1
- package/dist/assets/useNotebookActions-CQd8IgyR.js +1 -0
- package/dist/assets/useSplitCell-Dodncnp8.js +1 -0
- package/dist/assets/{useTheme-C5JyqXTm.js → useTheme-oPMxEKRc.js} +1 -1
- package/dist/assets/{utilities.esm-DbqS7Pjb.js → utilities.esm-DcV_e-D3.js} +1 -1
- package/dist/assets/utils-DBmmAf_K.js +1 -0
- package/dist/assets/variable-panel-BCihDsBL.js +1 -0
- package/dist/assets/{vega-component-D1ZJxK-L.js → vega-component-CWMEFM7y.js} +1 -1
- package/dist/assets/{vega-loader.browser.module-Jwd7L8Ye.js → vega-loader.browser.module-BkWiTok0.js} +1 -1
- package/dist/assets/{with-selector-CXhuorCH.js → with-selector-BmLsipPw.js} +1 -1
- package/dist/assets/{workflow-Covue_dW.js → workflow-DA01FBLw.js} +1 -1
- package/dist/assets/{wrench-DNJq8NCj.js → wrench-B2m2X1sb.js} +1 -1
- package/dist/assets/{write-secret-modal-qe46KOIw.js → write-secret-modal-Dx9oubag.js} +1 -1
- package/dist/assets/{xychartDiagram-6GGTOJPD-DK41sZTI.js → xychartDiagram-6GGTOJPD-D-i5LTeX.js} +1 -1
- package/dist/assets/{youtube-0-RiaVkr.js → youtube-Bl4NeyvA.js} +1 -1
- package/dist/index.html +155 -155
- package/package.json +1 -1
- package/src/__tests__/chat-history.test.ts +123 -0
- package/src/components/app-config/ai-config.tsx +23 -0
- package/src/components/app-config/mcp-config.tsx +42 -2
- package/src/components/app-config/user-config-form.tsx +0 -24
- package/src/components/chat/acp/__tests__/context-utils.test.ts +1 -1
- package/src/components/chat/acp/agent-panel.tsx +1 -1
- package/src/components/chat/acp/blocks.tsx +46 -53
- package/src/components/chat/acp/common.tsx +1 -1
- package/src/components/chat/acp/context-utils.ts +1 -1
- package/src/components/chat/acp/session-tabs.tsx +1 -1
- package/src/components/chat/chat-history-popover.tsx +125 -0
- package/src/components/chat/chat-history-utils.ts +69 -0
- package/src/components/chat/chat-panel.tsx +9 -57
- package/src/components/editor/__tests__/data-attributes.test.tsx +1 -1
- package/src/components/editor/actions/useNotebookActions.tsx +2 -4
- package/src/components/editor/ai/__tests__/completion-utils.test.ts +23 -31
- package/src/components/editor/cell/CreateCellButton.tsx +14 -2
- package/src/components/editor/cell/code/cell-editor.tsx +1 -0
- package/src/components/editor/database/schemas.ts +2 -10
- package/src/components/editor/{Cell.tsx → notebook-cell.tsx} +5 -1
- package/src/components/editor/output/MarimoErrorOutput.tsx +4 -34
- package/src/components/editor/renderers/{CellArray.tsx → cell-array.tsx} +1 -1
- package/src/components/forms/__tests__/form-utils.test.ts +2 -2
- package/src/components/mcp/hooks.ts +48 -0
- package/src/components/mcp/mcp-status-indicator.tsx +144 -0
- package/src/components/ui/number-field.tsx +4 -1
- package/src/core/ai/context/providers/__tests__/__snapshots__/tables.test.ts.snap +13 -19
- package/src/core/ai/context/providers/__tests__/cell-output.test.ts +0 -1
- package/src/core/ai/context/providers/__tests__/datasource.test.ts +5 -6
- package/src/core/ai/context/providers/__tests__/error.test.ts +24 -15
- package/src/core/ai/context/providers/cell-output.ts +5 -5
- package/src/core/ai/context/providers/common.ts +13 -4
- package/src/core/ai/context/providers/datasource.ts +31 -20
- package/src/core/ai/context/providers/error.ts +3 -4
- package/src/core/ai/context/providers/file.ts +2 -2
- package/src/core/ai/context/providers/tables.ts +36 -8
- package/src/core/ai/context/providers/variable.ts +2 -3
- package/src/core/cells/__tests__/cells.test.ts +6 -6
- package/src/core/cells/cells.ts +12 -13
- package/src/core/cells/scrollCellIntoView.ts +1 -1
- package/src/core/codemirror/__tests__/setup.test.ts +1 -0
- package/src/core/codemirror/cm.ts +3 -2
- package/src/core/config/__tests__/config-schema.test.ts +2 -0
- package/src/core/config/config-schema.ts +2 -0
- package/src/core/config/feature-flag.tsx +0 -2
- package/src/core/edit-app.tsx +1 -1
- package/src/core/network/CachingRequestRegistry.ts +2 -2
- package/src/stories/cell.stories.tsx +1 -1
- package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
- package/src/utils/numbers.ts +24 -1
- package/dist/assets/MarimoErrorOutput-CUb4AQdT.js +0 -6
- package/dist/assets/add-cell-with-ai-DCyfgnLI.js +0 -36
- package/dist/assets/agent-panel-B_MMb9mo.js +0 -287
- package/dist/assets/ai-model-dropdown-Dk9Kz_pz.js +0 -2
- package/dist/assets/api-DBBaApVO.js +0 -1
- package/dist/assets/app-config-button-Cbw9b5rl.js +0 -1
- package/dist/assets/cell-link-woRE950-.js +0 -1
- package/dist/assets/channel-D-YgrD6I.js +0 -1
- package/dist/assets/chat-panel-DLphumiN.js +0 -3
- package/dist/assets/check-hL6-9SZK.js +0 -1
- package/dist/assets/circle-check-big-C7DGeh12.js +0 -1
- package/dist/assets/classDiagram-KNZD7YFC-yzXw7kFX.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-Co2zbBi0.js +0 -1
- package/dist/assets/client-CA946N69.js +0 -2
- package/dist/assets/column-preview-BT14RHNM.js +0 -2
- package/dist/assets/command-palette-qYrNUNjA.js +0 -1
- package/dist/assets/datasources-panel-2YJ76Lq8.js +0 -1
- package/dist/assets/dependency-graph-panel-CnzvmPdT.js +0 -4
- package/dist/assets/dist-BtRvVXgu.js +0 -1
- package/dist/assets/dist-CAZ5kHnb.js +0 -1
- package/dist/assets/dist-CN8IvtVY.js +0 -1
- package/dist/assets/dist-Cw007UHk.js +0 -1
- package/dist/assets/dist-DEfSR7VW.js +0 -1
- package/dist/assets/dist-DSbiMNpu.js +0 -1
- package/dist/assets/dist-DeIZvG9x.js +0 -1
- package/dist/assets/dist-DyZWkD0n.js +0 -1
- package/dist/assets/dist-hfODPqg9.js +0 -1
- package/dist/assets/edit-page-Bt_YqRld.js +0 -12
- package/dist/assets/error-panel-dvBEznKE.js +0 -1
- package/dist/assets/esm-hOS9Yf3s.js +0 -1
- package/dist/assets/field-Ota1KKvP.js +0 -1
- package/dist/assets/file-explorer-panel-Pa89UfV1.js +0 -1
- package/dist/assets/filename-BYm5Do9U.js +0 -1
- package/dist/assets/home-page-B3bIZC6F.js +0 -4
- package/dist/assets/index-BQd14tU4.css +0 -2
- package/dist/assets/input-Dm-m3XYB.js +0 -7
- package/dist/assets/links-CQoApRoA.js +0 -1
- package/dist/assets/logs-panel-R50NxjC7.js +0 -1
- package/dist/assets/mermaid.core-BjBlUxCx.js +0 -1
- package/dist/assets/numbers-DtHKLeOn.js +0 -1
- package/dist/assets/outline-panel-CB2kV_p5.js +0 -1
- package/dist/assets/packages-panel-BpFuUbAr.js +0 -1
- package/dist/assets/run-page-ClDuCh42.js +0 -1
- package/dist/assets/scratchpad-panel-BRljth0m.js +0 -1
- package/dist/assets/secrets-panel-CQON2dfx.js +0 -1
- package/dist/assets/snippets-panel-C0OdhmTA.js +0 -1
- package/dist/assets/state-DaDgAzck.js +0 -1
- package/dist/assets/state-Do6Fn2Io.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-Bi0DZGHg.js +0 -1
- package/dist/assets/stex-CbLDtSMU.js +0 -1
- package/dist/assets/storage-DFOl3UlZ.js +0 -1
- package/dist/assets/tracing-k1M6Upka.js +0 -2
- package/dist/assets/tracing-panel-CyG4yTCu.js +0 -2
- package/dist/assets/useHotkey-CJ5v8JMM.js +0 -1
- package/dist/assets/useNotebookActions-BB-5-4dL.js +0 -1
- package/dist/assets/useSplitCell-Cy53n7mS.js +0 -1
- package/dist/assets/utils-CfnN8i3Y.js +0 -1
- package/dist/assets/variable-panel-Dd_6lOoR.js +0 -1
- /package/dist/assets/{Deferred-BIEvCvJC.js → Deferred-Mppm0cvJ.js} +0 -0
- /package/dist/assets/{alert-B2-Y1fzf.js → alert-hjKHAeOD.js} +0 -0
- /package/dist/assets/{badge-D5b5ze0K.js → badge-DJuT6BaT.js} +0 -0
- /package/dist/assets/{blob-DFrnsWYL.js → blob-CTPcPiam.js} +0 -0
- /package/dist/assets/{connection-Cb7zku0y.js → connection-D2GvycR9.js} +0 -0
- /package/dist/assets/{copy-BiKQh0sU.js → copy-CkZsxeON.js} +0 -0
- /package/dist/assets/{createLucideIcon-Be9UM2Pe.js → createLucideIcon-QLW8E4z5.js} +0 -0
- /package/dist/assets/{createReducer-BaSP2BKE.js → createReducer-CFr1RdS2.js} +0 -0
- /package/dist/assets/{defaultLocale-DU4zdxes.js → defaultLocale-C6TNIE_k.js} +0 -0
- /package/dist/assets/{defaultLocale-BCtmQtCj.js → defaultLocale-DPsgYaXf.js} +0 -0
- /package/dist/assets/{dist-DIuPmJ5w.js → dist-Bz53xjA5.js} +0 -0
- /package/dist/assets/{dist-BhR4qmIv.js → dist-DcASoeRZ.js} +0 -0
- /package/dist/assets/{dist-BMAXVGJe.js → dist-Dlusp3mb.js} +0 -0
- /package/dist/assets/{documentation-BZROoSma.js → documentation-B7z6bB-t.js} +0 -0
- /package/dist/assets/{emotion-is-prop-valid.esm-plUNooLR.js → emotion-is-prop-valid.esm-BbphD4LX.js} +0 -0
- /package/dist/assets/{errors-qtuExmE-.js → errors-_3XAtRr3.js} +0 -0
- /package/dist/assets/{es-Hxx5X1vH.js → es-BVCqnQhJ.js} +0 -0
- /package/dist/assets/{extends--r5KbeWh.js → extends-Bwhapo2B.js} +0 -0
- /package/dist/assets/{fast-deep-equal-DT2Tke28.js → fast-deep-equal-BdzBWnNx.js} +0 -0
- /package/dist/assets/{icons-BUUt9FMo.js → icons-CLD-J5J3.js} +0 -0
- /package/dist/assets/{kbd-DItNvBdP.js → kbd-BQFiWIjd.js} +0 -0
- /package/dist/assets/{main-Co0CqoDt.js → main-CfqcqCNp.js} +0 -0
- /package/dist/assets/{marked.esm-BVjBUuHx.js → marked.esm-C_54K2ke.js} +0 -0
- /package/dist/assets/{namespace-BstGchRe.js → namespace-CnoeT75h.js} +0 -0
- /package/dist/assets/{objectWithoutPropertiesLoose-CGYpiDu4.js → objectWithoutPropertiesLoose-CDpgRi8_.js} +0 -0
- /package/dist/assets/{ordinal-DO1z0TEs.js → ordinal-CHS6rGcb.js} +0 -0
- /package/dist/assets/{preload-helper-CxnU7XTI.js → preload-helper-DImqtvgl.js} +0 -0
- /package/dist/assets/{prop-types-Bv8iPqhZ.js → prop-types-CHKlDUlJ.js} +0 -0
- /package/dist/assets/{range-CJAH1fu_.js → range-BPiwmiGf.js} +0 -0
- /package/dist/assets/{shim-Bk8nzKPV.js → shim-CWt9rDBn.js} +0 -0
- /package/dist/assets/{stex-CETff8Y9.js → stex-BrOrfhKB.js} +0 -0
- /package/dist/assets/{strings-1yw0WVap.js → strings-DYBy5ejj.js} +0 -0
- /package/dist/assets/{tslib.es6-DItc8Tbq.js → tslib.es6-dlz5WbC8.js} +0 -0
- /package/dist/assets/{use-toast-C07-frN_.js → use-toast-D6NNsC80.js} +0 -0
- /package/dist/assets/{useEvent-BIiDVnhT.js → useEvent-BOb1a9d1.js} +0 -0
- /package/dist/assets/{useLifecycle-Bnvt0QrQ.js → useLifecycle-BfeAlD80.js} +0 -0
- /package/dist/assets/{useNonce-Cw4ZAbgi.js → useNonce-BbWkd3B4.js} +0 -0
- /package/dist/assets/{useNumberFormatter-DYIEUCTe.js → useNumberFormatter-D21brJ0f.js} +0 -0
- /package/dist/assets/{uuid-BWz20PcF.js → uuid-4lb_EYpq.js} +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
4
|
+
import { groupChatsByDate } from "../components/chat/chat-history-utils";
|
|
5
|
+
import type { Chat } from "../core/ai/state";
|
|
6
|
+
|
|
7
|
+
// Mock current time for consistent testing
|
|
8
|
+
const mockNow = new Date("2024-01-15T12:00:00Z").getTime();
|
|
9
|
+
|
|
10
|
+
// Mock Date.now to return our fixed time
|
|
11
|
+
const originalDateNow = Date.now;
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
Date.now = () => mockNow;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
Date.now = originalDateNow;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("groupChatsByDate", () => {
|
|
21
|
+
const createMockChat = (daysAgo: number, title: string): Chat => ({
|
|
22
|
+
id: `chat-${daysAgo}` as Chat["id"],
|
|
23
|
+
title,
|
|
24
|
+
messages: [],
|
|
25
|
+
createdAt: mockNow - daysAgo * 24 * 60 * 60 * 1000,
|
|
26
|
+
updatedAt: mockNow - daysAgo * 24 * 60 * 60 * 1000,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should group chats correctly by date periods", () => {
|
|
30
|
+
const chats: Chat[] = [
|
|
31
|
+
createMockChat(0, "Today chat"),
|
|
32
|
+
createMockChat(1, "Yesterday chat"),
|
|
33
|
+
createMockChat(2, "2 days ago chat"),
|
|
34
|
+
createMockChat(3, "3 days ago chat"),
|
|
35
|
+
createMockChat(5, "5 days ago chat"), // Should go to "This week"
|
|
36
|
+
createMockChat(10, "10 days ago chat"), // Should go to "This month"
|
|
37
|
+
createMockChat(40, "40 days ago chat"), // Should go to "Older"
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const result = groupChatsByDate(chats);
|
|
41
|
+
|
|
42
|
+
// Should have 7 groups
|
|
43
|
+
expect(result).toHaveLength(chats.length);
|
|
44
|
+
|
|
45
|
+
// Check Today group
|
|
46
|
+
const todayGroup = result.find((g) => g.label === "Today");
|
|
47
|
+
expect(todayGroup?.chats).toHaveLength(1);
|
|
48
|
+
expect(todayGroup?.chats[0].title).toBe("Today chat");
|
|
49
|
+
|
|
50
|
+
// Check Yesterday group
|
|
51
|
+
const yesterdayGroup = result.find((g) => g.label === "Yesterday");
|
|
52
|
+
expect(yesterdayGroup?.chats).toHaveLength(1);
|
|
53
|
+
expect(yesterdayGroup?.chats[0].title).toBe("Yesterday chat");
|
|
54
|
+
|
|
55
|
+
// Check 2d ago group
|
|
56
|
+
const twoDaysGroup = result.find((g) => g.label === "2d ago");
|
|
57
|
+
expect(twoDaysGroup?.chats).toHaveLength(1);
|
|
58
|
+
expect(twoDaysGroup?.chats[0].title).toBe("2 days ago chat");
|
|
59
|
+
|
|
60
|
+
// Check 3d ago group
|
|
61
|
+
const threeDaysGroup = result.find((g) => g.label === "3d ago");
|
|
62
|
+
expect(threeDaysGroup?.chats).toHaveLength(1);
|
|
63
|
+
expect(threeDaysGroup?.chats[0].title).toBe("3 days ago chat");
|
|
64
|
+
|
|
65
|
+
// Check This week group (should include 5)
|
|
66
|
+
const thisWeekGroup = result.find((g) => g.label === "This week");
|
|
67
|
+
expect(thisWeekGroup?.chats).toHaveLength(1);
|
|
68
|
+
expect(thisWeekGroup?.chats.map((c) => c.title)).toContain(
|
|
69
|
+
"5 days ago chat",
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Check This month group (should include 40 days ago)
|
|
73
|
+
const thisMonthGroup = result.find((g) => g.label === "This month");
|
|
74
|
+
expect(thisMonthGroup?.chats).toHaveLength(1);
|
|
75
|
+
expect(thisMonthGroup?.chats[0].title).toBe("10 days ago chat");
|
|
76
|
+
|
|
77
|
+
// Check Older group (should include 40 days ago)
|
|
78
|
+
const olderGroup = result.find((g) => g.label === "Older");
|
|
79
|
+
expect(olderGroup?.chats).toHaveLength(1);
|
|
80
|
+
expect(olderGroup?.chats[0].title).toBe("40 days ago chat");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should include all chats in some group", () => {
|
|
84
|
+
const chats: Chat[] = [
|
|
85
|
+
createMockChat(0, "Today"),
|
|
86
|
+
createMockChat(1, "Yesterday"),
|
|
87
|
+
createMockChat(2, "2 days ago"),
|
|
88
|
+
createMockChat(3, "3 days ago"),
|
|
89
|
+
createMockChat(5, "5 days ago"),
|
|
90
|
+
createMockChat(10, "10 days ago"),
|
|
91
|
+
createMockChat(20, "20 days ago"),
|
|
92
|
+
createMockChat(40, "40 days ago"),
|
|
93
|
+
createMockChat(100, "100 days ago"),
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
const result = groupChatsByDate(chats);
|
|
97
|
+
|
|
98
|
+
// Count total chats across all groups
|
|
99
|
+
const totalChatsInGroups = result.reduce(
|
|
100
|
+
(sum, group) => sum + group.chats.length,
|
|
101
|
+
0,
|
|
102
|
+
);
|
|
103
|
+
expect(totalChatsInGroups).toBe(chats.length);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should handle empty chat list", () => {
|
|
107
|
+
const result = groupChatsByDate([]);
|
|
108
|
+
expect(result).toHaveLength(0);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should filter out empty groups", () => {
|
|
112
|
+
const chats: Chat[] = [
|
|
113
|
+
createMockChat(0, "Today chat"),
|
|
114
|
+
createMockChat(40, "Old chat"),
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const result = groupChatsByDate(chats);
|
|
118
|
+
|
|
119
|
+
// Should only have Today and Older groups, not the empty ones in between
|
|
120
|
+
expect(result).toHaveLength(2);
|
|
121
|
+
expect(result.map((g) => g.label)).toEqual(["Today", "Older"]);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -930,6 +930,29 @@ export const AiAssistConfig: React.FC<AiConfigProps> = ({
|
|
|
930
930
|
return (
|
|
931
931
|
<SettingGroup>
|
|
932
932
|
<SettingSubtitle>AI Assistant</SettingSubtitle>
|
|
933
|
+
|
|
934
|
+
<FormField
|
|
935
|
+
control={form.control}
|
|
936
|
+
name="ai.inline_tooltip"
|
|
937
|
+
render={({ field }) => (
|
|
938
|
+
<div className="flex flex-col gap-y-1">
|
|
939
|
+
<FormItem className={formItemClasses}>
|
|
940
|
+
<FormLabel className="font-normal">AI Edit Tooltip</FormLabel>
|
|
941
|
+
<FormControl>
|
|
942
|
+
<Checkbox
|
|
943
|
+
data-testid="inline-ai-checkbox"
|
|
944
|
+
checked={field.value === true}
|
|
945
|
+
onCheckedChange={field.onChange}
|
|
946
|
+
/>
|
|
947
|
+
</FormControl>
|
|
948
|
+
</FormItem>
|
|
949
|
+
<FormDescription>
|
|
950
|
+
Enable "Edit with AI" tooltip when selecting code.
|
|
951
|
+
</FormDescription>
|
|
952
|
+
</div>
|
|
953
|
+
)}
|
|
954
|
+
/>
|
|
955
|
+
|
|
933
956
|
<FormErrorsBanner />
|
|
934
957
|
<ModelSelector
|
|
935
958
|
label="Chat Model"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { CheckSquareIcon } from "lucide-react";
|
|
3
|
+
import { CheckSquareIcon, Loader2, RefreshCwIcon } from "lucide-react";
|
|
4
4
|
import React from "react";
|
|
5
5
|
import type { UseFormReturn } from "react-hook-form";
|
|
6
6
|
import {
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
} from "@/components/ui/card";
|
|
13
13
|
import { FormField, FormItem } from "@/components/ui/form";
|
|
14
14
|
import type { UserConfig } from "@/core/config/config-schema";
|
|
15
|
+
import { useMCPRefresh, useMCPStatus } from "../mcp/hooks";
|
|
16
|
+
import { McpStatusText } from "../mcp/mcp-status-indicator";
|
|
15
17
|
import { Button } from "../ui/button";
|
|
16
18
|
import { Kbd } from "../ui/kbd";
|
|
17
19
|
import { SettingSubtitle } from "./common";
|
|
@@ -45,10 +47,48 @@ const PRESET_CONFIGS: PresetConfig[] = [
|
|
|
45
47
|
|
|
46
48
|
export const MCPConfig: React.FC<MCPConfigProps> = ({ form, onSubmit }) => {
|
|
47
49
|
const { handleClick } = useOpenSettingsToTab();
|
|
50
|
+
const { data: status, refetch, isFetching } = useMCPStatus();
|
|
51
|
+
const { refresh, isRefreshing } = useMCPRefresh();
|
|
52
|
+
|
|
53
|
+
const handleRefresh = async () => {
|
|
54
|
+
await refresh();
|
|
55
|
+
refetch();
|
|
56
|
+
};
|
|
48
57
|
|
|
49
58
|
return (
|
|
50
59
|
<div className="flex flex-col gap-4">
|
|
51
|
-
<
|
|
60
|
+
<div className="flex items-center justify-between">
|
|
61
|
+
<SettingSubtitle>MCP Servers</SettingSubtitle>
|
|
62
|
+
<div className="flex items-center gap-2">
|
|
63
|
+
{status && <McpStatusText status={status.status} />}
|
|
64
|
+
<Button
|
|
65
|
+
variant="outline"
|
|
66
|
+
size="xs"
|
|
67
|
+
onClick={handleRefresh}
|
|
68
|
+
disabled={isRefreshing || isFetching}
|
|
69
|
+
>
|
|
70
|
+
{isRefreshing || isFetching ? (
|
|
71
|
+
<Loader2 className="h-3 w-3 animate-spin" />
|
|
72
|
+
) : (
|
|
73
|
+
<RefreshCwIcon className="h-3 w-3" />
|
|
74
|
+
)}
|
|
75
|
+
</Button>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
{status?.error && (
|
|
79
|
+
<div className="text-xs text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-950/20 p-2 rounded">
|
|
80
|
+
{status.error}
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
{status?.servers && (
|
|
84
|
+
<div className="text-xs text-muted-foreground">
|
|
85
|
+
{Object.entries(status.servers).map(([server, status]) => (
|
|
86
|
+
<div key={server}>
|
|
87
|
+
{server}: <McpStatusText status={status} />
|
|
88
|
+
</div>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
)}
|
|
52
92
|
<p className="text-sm text-muted-foreground">
|
|
53
93
|
Enable Model Context Protocol (MCP) servers to provide additional
|
|
54
94
|
capabilities and data sources for AI features.
|
|
@@ -1228,30 +1228,6 @@ export const UserConfigForm: React.FC = () => {
|
|
|
1228
1228
|
notebook to take effect.
|
|
1229
1229
|
</p>
|
|
1230
1230
|
|
|
1231
|
-
<FormField
|
|
1232
|
-
control={form.control}
|
|
1233
|
-
name="experimental.inline_ai_tooltip"
|
|
1234
|
-
render={({ field }) => (
|
|
1235
|
-
<div className="flex flex-col gap-y-1">
|
|
1236
|
-
<FormItem className={formItemClasses}>
|
|
1237
|
-
<FormLabel className="font-normal">
|
|
1238
|
-
AI Edit Tooltip
|
|
1239
|
-
</FormLabel>
|
|
1240
|
-
<FormControl>
|
|
1241
|
-
<Checkbox
|
|
1242
|
-
data-testid="inline-ai-checkbox"
|
|
1243
|
-
checked={field.value === true}
|
|
1244
|
-
onCheckedChange={field.onChange}
|
|
1245
|
-
/>
|
|
1246
|
-
</FormControl>
|
|
1247
|
-
</FormItem>
|
|
1248
|
-
<FormDescription>
|
|
1249
|
-
Enable experimental "Edit with AI" tooltip when selecting
|
|
1250
|
-
code.
|
|
1251
|
-
</FormDescription>
|
|
1252
|
-
</div>
|
|
1253
|
-
)}
|
|
1254
|
-
/>
|
|
1255
1231
|
<FormField
|
|
1256
1232
|
control={form.control}
|
|
1257
1233
|
name="experimental.rtc_v2"
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
} from "@/components/ui/popover";
|
|
31
31
|
import { logNever } from "@/utils/assertNever";
|
|
32
32
|
import { cn } from "@/utils/cn";
|
|
33
|
-
import { type Base64String, base64ToDataURL } from "@/utils/json/base64";
|
|
34
33
|
import { Strings } from "@/utils/strings";
|
|
35
34
|
import { MarkdownRenderer } from "../markdown-renderer";
|
|
36
35
|
import { SimpleAccordion } from "./common";
|
|
@@ -289,7 +288,7 @@ export const PlansBlock = (props: { data: PlanNotificationEvent[] }) => {
|
|
|
289
288
|
|
|
290
289
|
export const UserMessagesBlock = (props: { data: UserNotificationEvent[] }) => {
|
|
291
290
|
return (
|
|
292
|
-
<div className="flex flex-col gap-2 text-muted-foreground border p-2 bg-background rounded break-words">
|
|
291
|
+
<div className="flex flex-col gap-2 text-muted-foreground border p-2 bg-background rounded break-words overflow-x-hidden">
|
|
293
292
|
<ContentBlocks data={props.data.map((item) => item.content)} />
|
|
294
293
|
</div>
|
|
295
294
|
);
|
|
@@ -364,58 +363,28 @@ export const ResourceBlock = (props: { data: ContentBlockOf<"resource"> }) => {
|
|
|
364
363
|
return (
|
|
365
364
|
<Popover>
|
|
366
365
|
<PopoverTrigger>
|
|
367
|
-
<span className="flex items-center gap-1">
|
|
366
|
+
<span className="flex items-center gap-1 hover:bg-muted rounded-md px-1">
|
|
368
367
|
{props.data.resource.mimeType && (
|
|
369
368
|
<MimeIcon mimeType={props.data.resource.mimeType} />
|
|
370
369
|
)}
|
|
371
370
|
{props.data.resource.uri}
|
|
372
371
|
</span>
|
|
373
372
|
</PopoverTrigger>
|
|
374
|
-
<PopoverContent className="max-h-96 overflow-y-auto scrollbar-thin">
|
|
375
|
-
<
|
|
373
|
+
<PopoverContent className="max-h-96 overflow-y-auto scrollbar-thin whitespace-pre-wrap w-full max-w-[500px]">
|
|
374
|
+
<span className="text-muted-foreground text-xs mb-1 italic">
|
|
375
|
+
Formatted for agents, not humans.
|
|
376
|
+
</span>
|
|
377
|
+
{props.data.resource.mimeType === "text/plain" ? (
|
|
378
|
+
<pre className="text-xs whitespace-pre-wrap p-2 bg-muted rounded-md break-words">
|
|
379
|
+
{props.data.resource.text}
|
|
380
|
+
</pre>
|
|
381
|
+
) : (
|
|
382
|
+
<MarkdownRenderer content={props.data.resource.text} />
|
|
383
|
+
)}
|
|
376
384
|
</PopoverContent>
|
|
377
385
|
</Popover>
|
|
378
386
|
);
|
|
379
387
|
}
|
|
380
|
-
|
|
381
|
-
if ("blob" in props.data.resource) {
|
|
382
|
-
if (props.data.resource.mimeType?.startsWith("image/")) {
|
|
383
|
-
return (
|
|
384
|
-
<ImageBlock
|
|
385
|
-
data={{
|
|
386
|
-
type: "image",
|
|
387
|
-
mimeType: props.data.resource.mimeType,
|
|
388
|
-
data: props.data.resource.blob,
|
|
389
|
-
}}
|
|
390
|
-
/>
|
|
391
|
-
);
|
|
392
|
-
}
|
|
393
|
-
if (props.data.resource.mimeType?.startsWith("audio/")) {
|
|
394
|
-
return (
|
|
395
|
-
<AudioBlock
|
|
396
|
-
data={{
|
|
397
|
-
type: "audio",
|
|
398
|
-
mimeType: props.data.resource.mimeType,
|
|
399
|
-
data: props.data.resource.blob,
|
|
400
|
-
}}
|
|
401
|
-
/>
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
const dataURL = base64ToDataURL(
|
|
405
|
-
props.data.resource.blob as Base64String,
|
|
406
|
-
props.data.resource.mimeType ?? "",
|
|
407
|
-
);
|
|
408
|
-
return (
|
|
409
|
-
<a href={dataURL} className="flex items-center gap-1" download={true}>
|
|
410
|
-
{props.data.resource.mimeType && (
|
|
411
|
-
<MimeIcon mimeType={props.data.resource.mimeType} />
|
|
412
|
-
)}
|
|
413
|
-
{props.data.resource.uri}
|
|
414
|
-
</a>
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
logNever(props.data.resource);
|
|
418
|
-
return null;
|
|
419
388
|
};
|
|
420
389
|
|
|
421
390
|
export const ResourceLinkBlock = (props: {
|
|
@@ -427,15 +396,38 @@ export const ResourceLinkBlock = (props: {
|
|
|
427
396
|
href={props.data.uri}
|
|
428
397
|
target="_blank"
|
|
429
398
|
rel="noopener noreferrer"
|
|
430
|
-
className="text-link hover:underline"
|
|
399
|
+
className="text-link hover:underline px-1"
|
|
431
400
|
>
|
|
432
401
|
{props.data.name}
|
|
433
402
|
</a>
|
|
434
403
|
);
|
|
435
404
|
}
|
|
436
405
|
|
|
406
|
+
// Show image in popover for image mime types
|
|
407
|
+
if (props.data.mimeType?.startsWith("image/")) {
|
|
408
|
+
return (
|
|
409
|
+
<div>
|
|
410
|
+
<Popover>
|
|
411
|
+
<PopoverTrigger>
|
|
412
|
+
<span className="flex items-center gap-1 hover:bg-muted rounded-md px-1 cursor-pointer">
|
|
413
|
+
<MimeIcon mimeType={props.data.mimeType} />
|
|
414
|
+
{props.data.name || props.data.title || props.data.uri}
|
|
415
|
+
</span>
|
|
416
|
+
</PopoverTrigger>
|
|
417
|
+
<PopoverContent className="w-auto max-w-[500px] p-2">
|
|
418
|
+
<img
|
|
419
|
+
src={props.data.uri}
|
|
420
|
+
alt={props.data.name || props.data.title || "Image"}
|
|
421
|
+
className="max-w-full max-h-96 object-contain"
|
|
422
|
+
/>
|
|
423
|
+
</PopoverContent>
|
|
424
|
+
</Popover>
|
|
425
|
+
</div>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
437
429
|
return (
|
|
438
|
-
<span className="flex items-center gap-1">
|
|
430
|
+
<span className="flex items-center gap-1 px-1">
|
|
439
431
|
{props.data.mimeType && <MimeIcon mimeType={props.data.mimeType} />}
|
|
440
432
|
{props.data.name || props.data.title || props.data.uri}
|
|
441
433
|
</span>
|
|
@@ -443,22 +435,23 @@ export const ResourceLinkBlock = (props: {
|
|
|
443
435
|
};
|
|
444
436
|
|
|
445
437
|
export const MimeIcon = (props: { mimeType: string }) => {
|
|
438
|
+
const classNames = "h-2 w-2 flex-shrink-0";
|
|
446
439
|
if (props.mimeType.startsWith("image/")) {
|
|
447
|
-
return <FileImageIcon className=
|
|
440
|
+
return <FileImageIcon className={classNames} />;
|
|
448
441
|
}
|
|
449
442
|
if (props.mimeType.startsWith("audio/")) {
|
|
450
|
-
return <FileAudio2Icon className=
|
|
443
|
+
return <FileAudio2Icon className={classNames} />;
|
|
451
444
|
}
|
|
452
445
|
if (props.mimeType.startsWith("video/")) {
|
|
453
|
-
return <FileVideoCameraIcon className=
|
|
446
|
+
return <FileVideoCameraIcon className={classNames} />;
|
|
454
447
|
}
|
|
455
448
|
if (props.mimeType.startsWith("text/")) {
|
|
456
|
-
return <FileTextIcon className=
|
|
449
|
+
return <FileTextIcon className={classNames} />;
|
|
457
450
|
}
|
|
458
451
|
if (props.mimeType.startsWith("application/")) {
|
|
459
|
-
return <FileJsonIcon className=
|
|
452
|
+
return <FileJsonIcon className={classNames} />;
|
|
460
453
|
}
|
|
461
|
-
return <FileIcon className=
|
|
454
|
+
return <FileIcon className={classNames} />;
|
|
462
455
|
};
|
|
463
456
|
|
|
464
457
|
export const SessionNotificationsBlock = <
|
|
@@ -533,7 +526,7 @@ export const ToolNotificationsBlock = (props: {
|
|
|
533
526
|
const toolCalls = mergeToolCalls(props.data);
|
|
534
527
|
|
|
535
528
|
return (
|
|
536
|
-
<div className="flex flex-col text-muted-foreground">
|
|
529
|
+
<div className="flex flex-col text-muted-foreground overflow-x-hidden">
|
|
537
530
|
{toolCalls.map((item) => (
|
|
538
531
|
<SimpleAccordion
|
|
539
532
|
key={item.toolCallId}
|
|
@@ -68,7 +68,7 @@ export const SimpleAccordion: React.FC<SimpleAccordionProps> = ({
|
|
|
68
68
|
>
|
|
69
69
|
<span className="flex items-center gap-1">
|
|
70
70
|
{getStatusIcon()}
|
|
71
|
-
<code className="font-mono text-xs">{title}</code>
|
|
71
|
+
<code className="font-mono text-xs truncate">{title}</code>
|
|
72
72
|
</span>
|
|
73
73
|
</AccordionTrigger>
|
|
74
74
|
<AccordionContent className="p-2">
|
|
@@ -30,7 +30,7 @@ const SessionTab: React.FC<SessionTabProps> = memo(
|
|
|
30
30
|
<div
|
|
31
31
|
className={cn(
|
|
32
32
|
"flex items-center gap-1 px-2 py-1 text-xs border-r border-border bg-muted/30 hover:bg-muted/50 cursor-pointer min-w-0",
|
|
33
|
-
isActive && "bg-background border-b-0 relative z-
|
|
33
|
+
isActive && "bg-background border-b-0 relative z-1",
|
|
34
34
|
)}
|
|
35
35
|
onClick={() => onSelect(session.tabId)}
|
|
36
36
|
>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
4
|
+
import { BotMessageSquareIcon, ClockIcon, SearchIcon } from "lucide-react";
|
|
5
|
+
import { useMemo, useState } from "react";
|
|
6
|
+
import { useLocale } from "react-aria";
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
|
+
import { Input } from "@/components/ui/input";
|
|
9
|
+
import {
|
|
10
|
+
Popover,
|
|
11
|
+
PopoverContent,
|
|
12
|
+
PopoverTrigger,
|
|
13
|
+
} from "@/components/ui/popover";
|
|
14
|
+
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
15
|
+
import { Tooltip } from "@/components/ui/tooltip";
|
|
16
|
+
import { type ChatId, chatStateAtom } from "@/core/ai/state";
|
|
17
|
+
import { cn } from "@/utils/cn";
|
|
18
|
+
import { timeAgo } from "@/utils/dates";
|
|
19
|
+
import { PanelEmptyState } from "../editor/chrome/panels/empty-state";
|
|
20
|
+
import { groupChatsByDate } from "./chat-history-utils";
|
|
21
|
+
|
|
22
|
+
interface ChatHistoryPopoverProps {
|
|
23
|
+
activeChatId: ChatId | undefined;
|
|
24
|
+
setActiveChat: (id: ChatId | null) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const ChatHistoryPopover: React.FC<ChatHistoryPopoverProps> = ({
|
|
28
|
+
activeChatId,
|
|
29
|
+
setActiveChat,
|
|
30
|
+
}) => {
|
|
31
|
+
const chatState = useAtomValue(chatStateAtom);
|
|
32
|
+
const { locale } = useLocale();
|
|
33
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
34
|
+
|
|
35
|
+
const chats = useMemo(() => {
|
|
36
|
+
return [...chatState.chats.values()].sort(
|
|
37
|
+
(a, b) => b.updatedAt - a.updatedAt,
|
|
38
|
+
);
|
|
39
|
+
}, [chatState.chats]);
|
|
40
|
+
|
|
41
|
+
const filteredChats = useMemo(() => {
|
|
42
|
+
if (!searchQuery.trim()) {
|
|
43
|
+
return chats;
|
|
44
|
+
}
|
|
45
|
+
return chats.filter((chat) =>
|
|
46
|
+
chat.title.toLowerCase().includes(searchQuery.toLowerCase()),
|
|
47
|
+
);
|
|
48
|
+
}, [chats, searchQuery]);
|
|
49
|
+
|
|
50
|
+
const groupedChats = useMemo(() => {
|
|
51
|
+
return groupChatsByDate(filteredChats);
|
|
52
|
+
}, [filteredChats]);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Popover>
|
|
56
|
+
<Tooltip content="Previous chats">
|
|
57
|
+
<PopoverTrigger asChild={true}>
|
|
58
|
+
<Button variant="text" size="icon">
|
|
59
|
+
<ClockIcon className="h-4 w-4" />
|
|
60
|
+
</Button>
|
|
61
|
+
</PopoverTrigger>
|
|
62
|
+
</Tooltip>
|
|
63
|
+
<PopoverContent className="w-[480px] p-0" align="start" side="right">
|
|
64
|
+
<div className="pt-3 px-3 w-full">
|
|
65
|
+
<Input
|
|
66
|
+
placeholder="Search chat history..."
|
|
67
|
+
value={searchQuery}
|
|
68
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
69
|
+
className="text-xs"
|
|
70
|
+
/>
|
|
71
|
+
</div>
|
|
72
|
+
<ScrollArea className="h-[450px] p-2">
|
|
73
|
+
<div className="space-y-3">
|
|
74
|
+
{chats.length === 0 && (
|
|
75
|
+
<PanelEmptyState
|
|
76
|
+
title="No chats yet"
|
|
77
|
+
description="Start a new chat to get started"
|
|
78
|
+
icon={<BotMessageSquareIcon />}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
81
|
+
{filteredChats.length === 0 && searchQuery && chats.length > 0 && (
|
|
82
|
+
<PanelEmptyState
|
|
83
|
+
title="No chats found"
|
|
84
|
+
description={`No chats match "${searchQuery}"`}
|
|
85
|
+
icon={<SearchIcon />}
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
{groupedChats.map((group, idx) => (
|
|
89
|
+
<div key={group.label} className="space-y-2">
|
|
90
|
+
<div className="text-xs px-1 text-muted-foreground/60">
|
|
91
|
+
{group.label}
|
|
92
|
+
</div>
|
|
93
|
+
<div>
|
|
94
|
+
{group.chats.map((chat) => (
|
|
95
|
+
<button
|
|
96
|
+
key={chat.id}
|
|
97
|
+
className={cn(
|
|
98
|
+
"w-full p-1 rounded-md cursor-pointer text-left flex items-center justify-between",
|
|
99
|
+
chat.id === activeChatId && "bg-accent",
|
|
100
|
+
chat.id !== activeChatId && "hover:bg-muted/20",
|
|
101
|
+
)}
|
|
102
|
+
onClick={() => {
|
|
103
|
+
setActiveChat(chat.id);
|
|
104
|
+
}}
|
|
105
|
+
type="button"
|
|
106
|
+
>
|
|
107
|
+
<div className="flex-1 min-w-0">
|
|
108
|
+
<div className="text-sm truncate">{chat.title}</div>
|
|
109
|
+
</div>
|
|
110
|
+
<div className="text-xs text-muted-foreground/60 ml-2 flex-shrink-0">
|
|
111
|
+
{timeAgo(chat.updatedAt, locale)}
|
|
112
|
+
</div>
|
|
113
|
+
</button>
|
|
114
|
+
))}
|
|
115
|
+
</div>
|
|
116
|
+
{/* If last group, don't show a divider */}
|
|
117
|
+
{idx !== groupedChats.length - 1 && <hr />}
|
|
118
|
+
</div>
|
|
119
|
+
))}
|
|
120
|
+
</div>
|
|
121
|
+
</ScrollArea>
|
|
122
|
+
</PopoverContent>
|
|
123
|
+
</Popover>
|
|
124
|
+
);
|
|
125
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { Chat } from "@/core/ai/state";
|
|
4
|
+
|
|
5
|
+
const DATE_GROUP_CONFIG = [
|
|
6
|
+
{ label: "Today", days: 0 },
|
|
7
|
+
{ label: "Yesterday", days: 1 },
|
|
8
|
+
{ label: "2d ago", days: 2 },
|
|
9
|
+
{ label: "3d ago", days: 3 },
|
|
10
|
+
{ label: "This week", days: 7 },
|
|
11
|
+
{ label: "This month", days: 30 },
|
|
12
|
+
] as const;
|
|
13
|
+
|
|
14
|
+
interface DateGroup {
|
|
15
|
+
label: string;
|
|
16
|
+
days: number;
|
|
17
|
+
chats: Chat[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Utility function to group chats by date periods
|
|
21
|
+
export const groupChatsByDate = (chats: Chat[]): DateGroup[] => {
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
const oneDayMs = 24 * 60 * 60 * 1000;
|
|
24
|
+
|
|
25
|
+
// Initialize groups with empty chat arrays
|
|
26
|
+
const groups: DateGroup[] = DATE_GROUP_CONFIG.map((config) => ({
|
|
27
|
+
...config,
|
|
28
|
+
chats: [],
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const olderGroup: DateGroup = {
|
|
32
|
+
label: "Older",
|
|
33
|
+
days: Infinity,
|
|
34
|
+
chats: [],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Helper function to determine which group a chat belongs to
|
|
38
|
+
const getGroupForChat = (daysDiff: number): DateGroup => {
|
|
39
|
+
// Use switch for exact day matches, then handle ranges
|
|
40
|
+
switch (daysDiff) {
|
|
41
|
+
case 0:
|
|
42
|
+
return groups[0]; // Today
|
|
43
|
+
case 1:
|
|
44
|
+
return groups[1]; // Yesterday
|
|
45
|
+
case 2:
|
|
46
|
+
return groups[2]; // 2d ago
|
|
47
|
+
case 3:
|
|
48
|
+
return groups[3]; // 3d ago
|
|
49
|
+
default:
|
|
50
|
+
// Handle range-based grouping for older chats
|
|
51
|
+
if (daysDiff >= 4 && daysDiff <= 7) {
|
|
52
|
+
return groups[4]; // This week
|
|
53
|
+
} else if (daysDiff >= 8 && daysDiff <= 30) {
|
|
54
|
+
return groups[5]; // This month
|
|
55
|
+
}
|
|
56
|
+
// Everything else goes to Older
|
|
57
|
+
return olderGroup;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
for (const chat of chats) {
|
|
62
|
+
const daysDiff = Math.floor((now - chat.updatedAt) / oneDayMs);
|
|
63
|
+
const targetGroup = getGroupForChat(daysDiff);
|
|
64
|
+
targetGroup.chats.push(chat);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Return only non-empty groups
|
|
68
|
+
return [...groups, olderGroup].filter((group) => group.chats.length > 0);
|
|
69
|
+
};
|