@marimo-team/islands 0.25.3-dev34 → 0.25.3-dev349
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/{ConnectedDataExplorerComponent-7EaP9VWb.js → ConnectedDataExplorerComponent-xliyyXNO.js} +188 -212
- package/dist/{ErrorBoundary-CkPa08Bb.js → ErrorBoundary-kxPR3skp.js} +79 -85
- package/dist/{ImageComparisonComponent-uU8FSKZE.js → ImageComparisonComponent-CoiwlCwG.js} +20 -20
- package/dist/{Plot-DdYOe1UK.js → Plot-BHJLG4xm.js} +2474 -3107
- package/dist/_baseSet-Bd5zh2yg.js +327 -0
- package/dist/{abnfDiagram-VCTEODGH-z_OSynK8.js → abnfDiagram-VCTEODGH-Dl9Nrtbf.js} +5 -5
- package/dist/any-language-editor-CBHhdCC0.js +75 -0
- package/dist/{apl-GEW9-ZP1.js → apl-stFrI2NB.js} +1 -1
- package/dist/{arc-7ra3iNdN.js → arc-4W6H62B5.js} +1 -1
- package/dist/architecture-7GRP2DOG-GlkXha5_.js +2 -0
- package/dist/{architectureDiagram-5GKGNRK7-Cs8J8BZr.js → architectureDiagram-5GKGNRK7-DTg032fQ.js} +48 -64
- package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
- package/dist/{asciiarmor-BWNxzkG7.js → asciiarmor-DHwFuaIC.js} +1 -1
- package/dist/{asn1-Bcn2QutK.js → asn1-KIH4fwAq.js} +1 -1
- package/dist/assertNever-ie77PjMn.js +507 -0
- package/dist/assets/__vite-browser-external-Ci3vRqC9.js +1 -0
- package/dist/assets/worker-D9NGcZWK.js +171 -0
- package/dist/{blockDiagram-I7D4REHJ-Cg25UrxT.js → blockDiagram-I7D4REHJ-BoCyD5KO.js} +28 -39
- package/dist/{brainfuck-BQCYDheZ.js → brainfuck-UPAij4U9.js} +1 -1
- package/dist/{button-CvjkwdSk.js → button-qQhINE7z.js} +64 -64
- package/dist/{c4Diagram-7LVT6UL2-BxFgrnNV.js → c4Diagram-7LVT6UL2-DmcTtm4p.js} +8 -8
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-DKqMqBzm.js} +2 -2
- package/dist/{channel-CPObtJXj.js → channel-B9eaiezW.js} +1 -1
- package/dist/{chat-ui-BeKQyQQI.js → chat-ui-BV0qyfru.js} +2551 -2390
- package/dist/{check-BMKBBrdc.js → check-DTIv5ZZ3.js} +1 -1
- package/dist/{chunk-4HAMMTFA-D4eFPyFh.js → chunk-4HAMMTFA-qKgadZwy.js} +6 -6
- package/dist/{chunk-75Z2AOVW-D7gxIs2Q.js → chunk-75Z2AOVW-76L6My3P.js} +4 -4
- package/dist/{chunk-YOKDWASO-DKplTrBY.js → chunk-7TTQLYRW-DBSfUUe5.js} +6253 -5835
- package/dist/{chunk-DU6HZSFF-BwiyaNpg.js → chunk-DU6HZSFF-4SDIhUTY.js} +14 -22
- package/dist/{chunk-F27PBJKO-ufseIn5y.js → chunk-F27PBJKO-COH2t-FO.js} +3 -3
- package/dist/{chunk-FOHPRMQF-BpYR8RqP.js → chunk-FOHPRMQF-ezmr_yWy.js} +49 -58
- package/dist/{chunk-GMAD6QVW-BhaJx0X3.js → chunk-GMAD6QVW-BJGF8QZL.js} +16 -75
- package/dist/{chunk-GVQU2GXP-Cwbt-lF0.js → chunk-GVQU2GXP-BkolpSXU.js} +3 -3
- package/dist/{chunk-IMKFNOWR-aoSFasqF.js → chunk-IMKFNOWR-CsFB-2LW.js} +8 -8
- package/dist/{chunk-L3NEJ4N5-n-zgIVSy.js → chunk-L3NEJ4N5-B-BFQp9t.js} +6 -6
- package/dist/{chunk-OSK3NFVY-DXa-Cxbn.js → chunk-OSK3NFVY-BzfZ4VBG.js} +8 -8
- package/dist/{chunk-P2QGCYS3-B_Zd3-X0.js → chunk-P2QGCYS3-DJApLVdt.js} +1 -1
- package/dist/{chunk-POPQ4Y6H-hYOXbYH_.js → chunk-POPQ4Y6H-BFSZel4w.js} +2 -2
- package/dist/{chunk-PWAF6VOD-CQw5qATZ.js → chunk-PWAF6VOD-CRu_RGP2.js} +2 -2
- package/dist/{chunk-SHT3W25Y-CMaybO3O.js → chunk-SHT3W25Y-ByuJHeBL.js} +10 -10
- package/dist/{chunk-SVP7TREG-BNBrTAw1.js → chunk-SVP7TREG-9oBZhbrr.js} +3 -3
- package/dist/{chunk-TICWLB2K-DXNxvUJn.js → chunk-TICWLB2K-Bx4m0cJ1.js} +10 -10
- package/dist/{chunk-XXDRQBXY-Dnl5VBqG.js → chunk-XXDRQBXY-BM-YIt-_.js} +1 -1
- package/dist/classDiagram-ZZMXUADV-Cms37-C9.js +30 -0
- package/dist/classDiagram-v2-VYDZK3BY-qAom4Bi7.js +30 -0
- package/dist/{clike-CxK9W55Z.js → clike-xU8sCVU1.js} +2 -6
- package/dist/{clojure-Dzcvwpxk.js → clojure-psoSEo36.js} +1 -1
- package/dist/{cmake-DYr-71zp.js → cmake-DDHBwlE7.js} +1 -1
- package/dist/{cobol-DC3g37Kq.js → cobol-C4qjDcIq.js} +1 -1
- package/dist/code-visibility-D8Fumu_H.js +130 -0
- package/dist/{coffeescript-C-eFwH5N.js → coffeescript-D6UgrGgo.js} +1 -1
- package/dist/{common-DCeV59yz.js → common-BwaJX-Um.js} +11323 -10613
- package/dist/{commonlisp-CyaNXrJR.js → commonlisp-B0ChVjnu.js} +1 -1
- package/dist/{compiler-runtime-CldRdSsv.js → compiler-runtime-C5KHtL5D.js} +3 -3
- package/dist/config-CvBnR945.js +618 -0
- package/dist/{copy-icon-BgUO8jsi.js → copy-icon-DmtNidSa.js} +21 -22
- package/dist/{cose-bilkent-JH36ORCC-_LyRKVqm.js → cose-bilkent-JH36ORCC-B_Oz4vMP.js} +58 -71
- package/dist/createReducer-BxBCTvKn.js +67 -0
- package/dist/{crystal-ih5ax5tQ.js → crystal-DZsc9Ue0.js} +1 -1
- package/dist/{css-CN_wP7_R.js → css-DkYRnQ9U.js} +1 -1
- package/dist/{cubic-OaEBhQPK.js → cubic-CA80xY_e.js} +6 -7
- package/dist/cynefin-OW5HDTMX-0-HehVvH.js +2 -0
- package/dist/{cynefinDiagram-5FMLGOSQ-DWHuKJs8.js → cynefinDiagram-5FMLGOSQ-BjJZwMEz.js} +5 -5
- package/dist/{cypher-CqGRcmZo.js → cypher-CpWPqgvy.js} +1 -1
- package/dist/{cytoscape.esm-jJhXJpLB.js → cytoscape.esm-BbeMznK5.js} +411 -512
- package/dist/{d-Cj0sOW2z.js → d-Bx2ggfYO.js} +1 -1
- package/dist/{dagre-BGSfXNEb.js → dagre-CpjuekF1.js} +550 -700
- package/dist/{dagre-GXQ25YYZ-DYLu-OCU.js → dagre-GXQ25YYZ-Bohu7_09.js} +14 -16
- package/dist/{data-grid-overlay-editor-DOGpF5cl.js → data-grid-overlay-editor-xN2CoaW7.js} +8 -8
- package/dist/{data-grid-types-0PJ-9N5n.js → data-grid-types-DIX_pCco.js} +2 -2
- package/dist/{debounce-C3jyATpc.js → debounce-DrhhziJv.js} +2 -2
- package/dist/{diagram-S7CK7UJ4-PwwcUOHP.js → diagram-S7CK7UJ4-Chl0n835.js} +7 -15
- package/dist/{diagram-UQ7AKVKN-CvJbL_IM.js → diagram-UQ7AKVKN-DHx8nzy7.js} +5 -5
- package/dist/{diagram-VSXAHHWV-BJWcVVJY.js → diagram-VSXAHHWV-LXjisZoM.js} +6 -6
- package/dist/{diagram-VX7I27RA-B5RkqnzN.js → diagram-VX7I27RA-CKdpv1U4.js} +7 -7
- package/dist/{diagram-Z3DM3KII-CyijwTR2.js → diagram-Z3DM3KII-sY-sI--2.js} +5 -5
- package/dist/{dialog-Cc479ZEH.js → dialog-Cqu5Hp5U.js} +32 -32
- package/dist/{diff-B_hUkiat.js → diff-DNXaJS8v.js} +1 -1
- package/dist/{dist-D6d86eNJ.js → dist-B-Id1kt3.js} +48 -47
- package/dist/{dist-DiDibOYr.js → dist-BDw9g6PC.js} +152 -151
- package/dist/{dist-diIx5qJW.js → dist-B_EswY8r.js} +33 -32
- package/dist/{dist-DoE4XJBC.js → dist-B_xgcU0N.js} +9800 -10654
- package/dist/{dist-CLdpGQVr.js → dist-BcGGwW1q.js} +119 -121
- package/dist/dist-BdZQUzPS.js +850 -0
- package/dist/{dist-CN_BeG2I.js → dist-Bj8s59mu.js} +59 -58
- package/dist/{dist-CkTTIdBe.js → dist-C3dYgyiI.js} +337 -337
- package/dist/{dist-PXYI_yuP.js → dist-C6ttp2Iy.js} +24 -23
- package/dist/{dist-DUAh96QY.js → dist-CB9MzCXv.js} +1 -1
- package/dist/{dist-CSbh1PNP.js → dist-CCYz0qJ2.js} +24 -23
- package/dist/{dist-BMQf5zIS.js → dist-CDjivQ67.js} +124 -123
- package/dist/{dist-D-wwqlzJ.js → dist-CNT4u03u.js} +159 -158
- package/dist/{dist-Lm-D-Vr6.js → dist-CiSkXlAO.js} +3 -3
- package/dist/{dist-F8Ep36rk.js → dist-DVVzH9mP.js} +60 -59
- package/dist/{dist-OR1OnN-y.js → dist-DlniJvh2.js} +32 -31
- package/dist/{dist-CSJ0MDRw.js → dist-Dq-hanx8.js} +57 -56
- package/dist/{dist-C8fAKSH1.js → dist-FakvNY2e.js} +54 -53
- package/dist/{dist-BuaRHxOc.js → dist-K-qmZv0f.js} +45 -44
- package/dist/{dist-Cg7gzw-a.js → dist-NPImE_g9.js} +79 -78
- package/dist/{dist-CN8zI-XC.js → dist-PKX4HaX5.js} +239 -239
- package/dist/{dist-CrSP_H1M.js → dist-U4WlxEDL.js} +243 -243
- package/dist/{dist-BK4Oj99o.js → dist-UKKHsqHo.js} +19 -18
- package/dist/{dist-Bvs24R_E.js → dist-VRN9rDqa.js} +32 -31
- package/dist/{dist-BorMD-uX.js → dist-f1h5p-fp.js} +76 -75
- package/dist/{dist-BLfKmR-l.js → dist-h8Te4SvD.js} +17 -16
- package/dist/{dist-DBtSl3sf.js → dist-ymIUQ4tH.js} +48 -50
- package/dist/dropdown-menu-DXEYk99S.js +5982 -0
- package/dist/{dtd-B8FGSWWe.js → dtd-D1YZQCVT.js} +1 -1
- package/dist/{dylan-DbIBYIrw.js → dylan-CxbG-PUm.js} +2 -2
- package/dist/{ebnfDiagram-PWID7BFC-DG90ELFp.js → ebnfDiagram-PWID7BFC-CD0P2xeH.js} +5 -5
- package/dist/{ecl-DBmkdWAd.js → ecl-DIXH6vul.js} +1 -1
- package/dist/{eiffel-CcWSDDzK.js → eiffel-D0de-eQr.js} +1 -1
- package/dist/{elm-MC-b8a6C.js → elm-DrQrn4VD.js} +1 -1
- package/dist/{erDiagram-RLTQ6QDP-FMo_SpyX.js → erDiagram-RLTQ6QDP-BaKQuYxC.js} +14 -14
- package/dist/{erlang-AdO1-xtV.js → erlang-2KpKpfC7.js} +1 -1
- package/dist/{error-banner-CFPHFw4h.js → error-banner-DUB_qUeL.js} +140 -140
- package/dist/error-entries-CTb_cxXY.js +2651 -0
- package/dist/{esm-G4Fhsgng.js → esm-DQtHTnHn.js} +640 -660
- package/dist/{esm-AMFssoNp.js → esm-Dc_RPXvZ.js} +335 -335
- package/dist/{esm-D2gTsXEV.js → esm-wKplZtOX.js} +580 -581
- package/dist/eventmodeling-NTZA5JFV-DoBvB4Lj.js +2 -0
- package/dist/{factor-Ys-13HOP.js → factor-Bwu3ZGOk.js} +1 -1
- package/dist/{feedback-button-HmgYHka9.js → feedback-button-C1UwtVjl.js} +105 -114
- package/dist/flowDiagram-HODETNUW-BcCpHh7-.js +15 -0
- package/dist/{formats-DRHUWwSK.js → formats-hF6fETr6.js} +9 -9
- package/dist/{forth-DiMuIXFe.js → forth-DYatDpr6.js} +2 -3
- package/dist/{fortran-hkrF2eM4.js → fortran-n8mcQPkL.js} +1 -1
- package/dist/{ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js → ganttDiagram-EL5Y4UJY-YzTghq1V.js} +17 -17
- package/dist/{gas-DlhqN9k8.js → gas-BUZOHBVw.js} +1 -1
- package/dist/{gherkin-0SlhEZ3t.js → gherkin-CrSjX26K.js} +1 -1
- package/dist/gitGraph-4MIJSDKK-Ch7kj-d2.js +2 -0
- package/dist/{gitGraphDiagram-WWUBYQGX-D5nSIzdE.js → gitGraphDiagram-WWUBYQGX-CK66dT35.js} +4 -4
- package/dist/{glide-data-editor-ChLxq3bk.js → glide-data-editor-o_BhuAJB.js} +6732 -2978
- package/dist/{glide-utils-pisbYVjH.js → glide-utils-Bnd_k48H.js} +109 -78
- package/dist/{globals-CP_-MiOh.js → globals-HTpXpd2Q.js} +3 -3
- package/dist/{graphlib-BmY_CCV9.js → graphlib-nlwT3Wvy.js} +177 -220
- package/dist/{groovy-YhcTMyvX.js → groovy-IgGNjeU9.js} +1 -1
- package/dist/hasIn-C20JsQ2m.js +28 -0
- package/dist/{haskell-CodLxrtT.js → haskell-Bs1k3a9s.js} +1 -1
- package/dist/{haxe-CiRWNFkH.js → haxe-CQ8Yb3XF.js} +1 -1
- package/dist/highlighted-body-JLMTFACH-yt0ZZn80.js +42 -0
- package/dist/{error-entries-CnqKxhU9.js → html-to-image-Bbl0PeC7.js} +26184 -26482
- package/dist/{idl-DZgBq75I.js → idl-DjnxoAWx.js} +1 -1
- package/dist/info-A6RAGUB7-DCz_Egh9.js +2 -0
- package/dist/{infoDiagram-27XIBGKW-CRSDtRrd.js → infoDiagram-27XIBGKW-DWltseIa.js} +4 -4
- package/dist/isArrayLikeObject-B-HXCsex.js +626 -0
- package/dist/isEmpty-CdX7MTE1.js +14 -0
- package/dist/{ishikawaDiagram-5VMMS53U-DxLEUldB.js → ishikawaDiagram-5VMMS53U-DHgepBPo.js} +5 -7
- package/dist/{javascript-BfNytHiM.js → javascript-BQtCoAFy.js} +2 -2
- package/dist/{journeyDiagram-3NMN7TZE-BaLqn-dZ.js → journeyDiagram-3NMN7TZE-CYXsL3IE.js} +4 -4
- package/dist/{jsx-runtime-3BD1kT0s.js → jsx-runtime-D8btoEHk.js} +2 -2
- package/dist/{julia--tLIAG7q.js → julia-BfgtHJE5.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-BLhvu8o4.js → kanban-definition-UXKFOSKX-B2_BIjBq.js} +10 -10
- package/dist/{katex-BIdZGsyO.js → katex-wAapZGrX.js} +793 -724
- package/dist/linear-TJTTbHM9.js +203 -0
- package/dist/{livescript-CVPfYnY_.js → livescript-gIdRPKtg.js} +1 -1
- package/dist/{loader-BPdQhmlq.js → loader-Bin_dutt.js} +13 -13
- package/dist/{lua-4Fa-T-qq.js → lua-CxFpWvnv.js} +2 -2
- package/dist/main.js +10930 -8473
- package/dist/{mathematica-CtYAy6GG.js → mathematica-QSveeEoW.js} +1 -1
- package/dist/{mbox-D0w9Ah1C.js → mbox-2JtaCPNT.js} +1 -1
- package/dist/{mermaid-Bjm6C1qN.js → mermaid--2K0cmt9.js} +170 -176
- package/dist/mermaid-WFAXDIZX-DHB2z13u.js +1 -0
- package/dist/{mermaid-parser.core-DxuSfYwJ.js → mermaid-parser.core-DtOnl7m4.js} +19 -25
- package/dist/{mhchem-CdWPJK6g.js → mhchem-CX8M7Ktl.js} +1 -1
- package/dist/{micromark-factory-space-DGxAzmw8.js → micromark-factory-space-C5soVmaM.js} +1 -1
- package/dist/{mindmap-definition-YA3MSWOX-g2LwxnYQ.js → mindmap-definition-YA3MSWOX-DNebycIP.js} +13 -13
- package/dist/{mirc-De9aSAZM.js → mirc-BqD6ade4.js} +1 -1
- package/dist/{mllike-BbugeaY_.js → mllike-CT0hgEOO.js} +1 -1
- package/dist/{modelica-BjJwWw1F.js → modelica-DKKebcvq.js} +1 -1
- package/dist/{mscgen-DwiRH5ma.js → mscgen-BJCCsWjR.js} +1 -1
- package/dist/{mumps--plbDM9o.js → mumps-DVQAXZkU.js} +1 -1
- package/dist/{nginx-C4Df7REc.js → nginx-AP4LH2NN.js} +1 -1
- package/dist/{node-sql-parser-BiZOJ-FS.js → node-sql-parser-C9dndbfr.js} +7184 -7195
- package/dist/{now-jM8-M7IR.js → now-BKZCLE5P.js} +12 -13
- package/dist/{nsis-fiiOqLc3.js → nsis-Cah9xkdT.js} +1 -1
- package/dist/{ntriples-jV77I4k8.js → ntriples-CQoaLOV6.js} +2 -2
- package/dist/{number-overlay-editor-CCm8xv1J.js → number-overlay-editor-Dmo99-rX.js} +17 -22
- package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
- package/dist/{octave-Cztd01tF.js → octave-CeDj2bTn.js} +1 -1
- package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
- package/dist/{oz-Bl8o3BDl.js → oz-BksQrg3k.js} +1 -1
- package/dist/packet-AYTQ26CC-DEMHgLPq.js +2 -0
- package/dist/{pascal-BO5JqysR.js → pascal-BKL17mpl.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-CpMAt3Qs.js → pegDiagram-XKGWAZYB-CH4U3II-.js} +5 -5
- package/dist/pencil-MMnw1YQh.js +10 -0
- package/dist/{perl-Drlh9s6m.js → perl-CacqJ-Ss.js} +1 -1
- package/dist/pick-DgpAbcwP.js +35 -0
- package/dist/pie-WAS4IAKB-DMjTEeHd.js +2 -0
- package/dist/{pieDiagram-E7YTZNPT-CVTthoZo.js → pieDiagram-E7YTZNPT-pfcrdUCa.js} +7 -7
- package/dist/{pig-BWGR8wZw.js → pig-CXSGZ_K9.js} +1 -1
- package/dist/{powershell-DT99xlz_.js → powershell-DY_yIxBM.js} +3 -6
- package/dist/precisionRound-DMIVQrt2.js +97 -0
- package/dist/{process-output-DgQrilBD.js → process-output-Dw_sI4Xp.js} +6 -6
- package/dist/{properties-Q-rkxld0.js → properties-Om0IDE07.js} +1 -1
- package/dist/{protobuf-DKyWZbs7.js → protobuf-B8nxxb4Q.js} +1 -1
- package/dist/{pug-42ZJUbEC.js → pug-lkUBPvVS.js} +3 -7
- package/dist/{puppet-B4UozHhh.js → puppet-DMkXsi4d.js} +1 -1
- package/dist/purify.es-DmnrIjg4.js +877 -0
- package/dist/{python-DREjAV__.js → python-JQVycMgr.js} +1 -1
- package/dist/{q-Bi63IpBO.js → q-DqE__nNB.js} +1 -1
- package/dist/{quadrantDiagram-AXDQQJYC-Blrm7V7_.js → quadrantDiagram-AXDQQJYC-nGFBFig7.js} +3 -3
- package/dist/{r-DSwXWKMR.js → r-Cbliap7Q.js} +1 -1
- package/dist/radar-RG4KPBEZ-9PwdCvai.js +2 -0
- package/dist/railroad-74A4TZTK-8N9kF5jl.js +2 -0
- package/dist/railroad-abnf-HS5TGJTU-Sg6YmzlR.js +2 -0
- package/dist/railroad-ebnf-LZEXJU2U-CYwp2Oee.js +2 -0
- package/dist/railroad-peg-WCYAUIDC-BfDkAuQ3.js +2 -0
- package/dist/{railroadDiagram-O6MQD6OU-ao8cqqFB.js → railroadDiagram-O6MQD6OU-BZKpAbNG.js} +5 -5
- package/dist/{react-sHtZdjeP.js → react-Bgs_wQh3.js} +3 -3
- package/dist/{react-dom-DUmH0GXv.js → react-dom-DdqGVp5N.js} +5 -5
- package/dist/{react-vega-BDpbvBCb.js → react-vega-CGgQEf0O.js} +13800 -17236
- package/dist/{requirementDiagram-BXWQKSXE--J8vyfm-.js → requirementDiagram-BXWQKSXE-DnyfIHe3.js} +13 -13
- package/dist/{reveal-component-C3tSBdGZ.js → reveal-component-SAEDhB8R.js} +1172 -1285
- package/dist/{rolldown-runtime-Cb76FRpK.js → rolldown-runtime-BPCzCO3I.js} +1 -1
- package/dist/{rpm-DPb1DeKM.js → rpm-DmT_LNpE.js} +1 -1
- package/dist/{ruby-U7fZA4DP.js → ruby-BHVZTtLW.js} +1 -1
- package/dist/{sankeyDiagram-P5KCCOFB-ELvOcnZH.js → sankeyDiagram-P5KCCOFB-CrOfyc2n.js} +2 -2
- package/dist/{sas-CLk1JpTn.js → sas-CrG5N1he.js} +1 -1
- package/dist/{scheme-CT-2k2Tl.js → scheme-BHUnz-IB.js} +1 -1
- package/dist/select-suaAxFuo.js +1200 -0
- package/dist/{semaphore-89jsoHtS.js → semaphore-8KhQouXt.js} +4 -5
- package/dist/{sequenceDiagram-WJ2MYXX4-CiQbn62x.js → sequenceDiagram-WJ2MYXX4-BeYuWX7N.js} +6 -6
- package/dist/{shell-BLO7fcsk.js → shell-C5IBmRU5.js} +1 -1
- package/dist/{sieve-nG3C7WNH.js → sieve-BzCnt_E6.js} +2 -2
- package/dist/{sizeCapture-INFHLROL-Dx5SpkQF.js → sizeCapture-INFHLROL-DBeZ20mI.js} +1 -1
- package/dist/{smalltalk-BROcZybA.js → smalltalk-DQFAQul3.js} +1 -1
- package/dist/{solr-mVltHNc5.js → solr-BiapYPCk.js} +1 -1
- package/dist/{sparql-Cv1Ksr4v.js → sparql-BcUKO1is.js} +1 -1
- package/dist/{spec-D_u2ipzF.js → spec-BQNx2-D7.js} +42 -12
- package/dist/{src-CA_m4ONl.js → src-D5uZaZib.js} +8 -14
- package/dist/{stateDiagram-D77RDMKH-DVEeGs5b.js → stateDiagram-D77RDMKH-B8FxwAM2.js} +18 -18
- package/dist/stateDiagram-v2-MP3YSRHH-CzWLBqm1.js +30 -0
- package/dist/static-state-Al_hmf1n.js +68 -0
- package/dist/{stex-Btf3omL8.js → stex-CQ_aCGTF.js} +1 -1
- package/dist/style.css +1 -1
- package/dist/{stylus-Dt4VvLXL.js → stylus-D4gHF5lg.js} +1 -1
- package/dist/{swift-DHsn_CVI.js → swift-CnvIBnbt.js} +1 -1
- package/dist/{swimlanes-42K2YHIH-CqkGoGqn.js → swimlanes-42K2YHIH-CzKmGMts.js} +37 -59
- package/dist/swimlanesDiagram-VR7AAH4N-DnWIUN_9.js +30 -0
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-DTdNB9wg.js} +45 -78
- package/dist/{tcl-CV0OLBOl.js → tcl-DkOjjZYO.js} +1 -1
- package/dist/{textile-D320oKVM.js → textile-DgzBVSEW.js} +1 -1
- package/dist/{tiki-BF2aDPlB.js → tiki-MighF8A_.js} +1 -1
- package/dist/{time-BaMbJs4z.js → time-BlOl70lB.js} +19 -19
- package/dist/{timeline-definition-24CTP7MA-DLRUNVAx.js → timeline-definition-24CTP7MA-Czf2QN2R.js} +5 -5
- package/dist/toast-CsJa1nGj.js +491 -0
- package/dist/{toml-CaUN7UHo.js → toml-B0B7UAba.js} +1 -1
- package/dist/{tooltip-CtBZ5q8p.js → tooltip-BVbJPkcl.js} +321 -297
- package/dist/treeView-Q6P3EWNA-BQywp0E1.js +2 -0
- package/dist/treemap-WGGIJYW6-P2ZJnldw.js +2 -0
- package/dist/{troff-DQUFcClZ.js → troff-B4IRX71y.js} +1 -1
- package/dist/{ttcn-CQL1duJS.js → ttcn-B4tpvdJD.js} +1 -1
- package/dist/{ttcn-cfg-BMmEFJPu.js → ttcn-cfg-pfE-1FV8.js} +1 -1
- package/dist/{turtle-C3esgsRr.js → turtle-Bc97ufp6.js} +1 -1
- package/dist/use-restore-focus-tPmARo1Q.js +7641 -0
- package/dist/{use-vega-container-remeasure-Bz4PZMtt.js → use-vega-container-remeasure-BrUpWQfF.js} +4 -8
- package/dist/{useAsyncData-BneN349z.js → useAsyncData-P5-Oovhq.js} +21 -20
- package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-B4ygYuUU.js} +5 -5
- package/dist/{useDeepCompareMemoize-Z_7R8wTt.js → useDeepCompareMemoize-Bcu0DkCS.js} +3 -3
- package/dist/useEvent-BoN7U38T.js +19 -0
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-HTZiVlGV.js} +2 -2
- package/dist/useLifecycle-MTdtnR3-.js +112 -0
- package/dist/{vb-RK1eDXRl.js → vb-C5kpOY_q.js} +1 -1
- package/dist/{vbscript-BCOeM0de.js → vbscript-Ck0hgOg5.js} +1 -1
- package/dist/{vega-component-1lFfDE_8.js → vega-component-BhBbP4S7.js} +167 -172
- package/dist/{vega-embed-container-BgKnsDbB.js → vega-embed-container-DgpACsCB.js} +7 -7
- package/dist/{vega-loader.browser-CpbZAXub.js → vega-loader.browser-Co9gYE8Z.js} +638 -295
- package/dist/{velocity-CZKOFbOI.js → velocity-2Doc6dgJ.js} +1 -1
- package/dist/{vennDiagram-4TSXK5OY-CypgoBVZ.js → vennDiagram-4TSXK5OY-BrHqWB1U.js} +4 -4
- package/dist/{verilog-DqQTzVn8.js → verilog-CmZmYe4R.js} +2 -2
- package/dist/{vhdl-vQr2bfmi.js → vhdl-esMnUHZm.js} +1 -1
- package/dist/wardley-WFR3VGLG-CIBJ6O2G.js +2 -0
- package/dist/{wardleyDiagram-VM6X3IG4-B6xjiQ_g.js → wardleyDiagram-VM6X3IG4-Cms1K_3v.js} +5 -5
- package/dist/{webidl-DzX7N40e.js → webidl-G_RlXG7G.js} +1 -1
- package/dist/{xquery-Cw_Q_hGR.js → xquery-IUQpMoMl.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-e0PefDVs.js → xychartDiagram-S5SC5T6Z-_kUiODzS.js} +8 -8
- package/dist/{yacas-DiC4jJBE.js → yacas-ObL0t2h9.js} +1 -1
- package/dist/{z80-CUOQDEJO.js → z80-jyuJhy0k.js} +1 -1
- package/package.json +37 -42
- package/src/__mocks__/document.tsx +63 -0
- package/src/__mocks__/executions.ts +219 -0
- package/src/__mocks__/notebook.ts +3 -7
- package/src/__mocks__/partial.ts +26 -0
- package/src/__mocks__/requests.ts +1 -7
- package/src/__tests__/CellStatus.test.tsx +25 -26
- package/src/__tests__/fixtures/pair-config.ts +1 -1
- package/src/__tests__/main.test.tsx +24 -1
- package/src/__tests__/module-entry.test.ts +44 -0
- package/src/__tests__/mount.test.ts +17 -78
- package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
- package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
- package/src/components/ai/__tests__/ai-utils.test.ts +8 -0
- package/src/components/ai/ai-model-dropdown.tsx +11 -6
- package/src/components/app-config/__tests__/state.test.tsx +50 -0
- package/src/components/app-config/ai-config.tsx +154 -150
- package/src/components/app-config/app-config-button.tsx +6 -5
- package/src/components/app-config/app-config-form.tsx +5 -9
- package/src/components/app-config/common.tsx +7 -9
- package/src/components/app-config/data-form.tsx +113 -116
- package/src/components/app-config/get-dirty-values.ts +4 -4
- package/src/components/app-config/mcp-config.tsx +30 -53
- package/src/components/app-config/user-config-form.css +91 -0
- package/src/components/app-config/user-config-form.tsx +266 -349
- package/src/components/chat/__tests__/capabilities-popover.test.tsx +0 -1
- package/src/components/chat/__tests__/chat-display.test.tsx +196 -0
- package/src/components/chat/__tests__/chat-markdown.test.tsx +43 -0
- package/src/components/chat/__tests__/chat-utils.test.ts +93 -1
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
- package/src/components/chat/__tests__/notebook-context.test.ts +199 -0
- package/src/components/chat/__tests__/turn-timing.test.ts +84 -0
- package/src/components/chat/__tests__/use-assistant-turn.test.ts +95 -0
- package/src/components/chat/__tests__/user-message.test.tsx +27 -0
- package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +1 -1
- package/src/components/chat/acp/__tests__/agent-panel.test.tsx +22 -17
- package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
- package/src/components/chat/acp/__tests__/state.test.ts +2 -2
- package/src/components/chat/acp/agent-panel.tsx +6 -3
- package/src/components/chat/acp/blocks.tsx +13 -12
- package/src/components/chat/acp/common.tsx +4 -5
- package/src/components/chat/acp/model-selector.tsx +1 -1
- package/src/components/chat/acp/session-tabs.tsx +8 -3
- package/src/components/chat/agent-activity.tsx +132 -0
- package/src/components/chat/capabilities-popover.tsx +2 -11
- package/src/components/chat/chat-components.tsx +9 -4
- package/src/components/chat/chat-display.tsx +131 -57
- package/src/components/chat/chat-history-popover.tsx +6 -1
- package/src/components/chat/chat-markdown.tsx +15 -0
- package/src/components/chat/chat-panel.tsx +249 -309
- package/src/components/chat/chat-typography.css +108 -0
- package/src/components/chat/chat-utils.ts +24 -35
- package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
- package/src/components/chat/notebook-access-selector.tsx +100 -0
- package/src/components/chat/notebook-context.ts +80 -0
- package/src/components/chat/tool-call/__tests__/tool-labels.test.ts +76 -0
- package/src/components/chat/tool-call/__tests__/tool-step.test.tsx +57 -0
- package/src/components/chat/tool-call/shared.ts +6 -0
- package/src/components/chat/tool-call/tool-call-view.tsx +22 -76
- package/src/components/chat/tool-call/tool-labels.ts +172 -0
- package/src/components/chat/tool-call/tool-result.tsx +1 -1
- package/src/components/chat/tool-call/tool-step.tsx +145 -0
- package/src/components/chat/turn-timing.ts +73 -0
- package/src/components/chat/use-assistant-turn.ts +65 -0
- package/src/components/chat/use-chat-generation.ts +20 -0
- package/src/components/chat/user-message.tsx +145 -0
- package/src/components/data-table/TableBottomBar.tsx +4 -1
- package/src/components/data-table/TableTopBar.tsx +2 -0
- package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
- package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
- package/src/components/data-table/__tests__/columns.test.tsx +105 -0
- package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
- package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
- package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
- package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
- package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
- package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
- package/src/components/data-table/cell-selection/feature.ts +2 -2
- package/src/components/data-table/cell-selection/types.ts +2 -2
- package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
- package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
- package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
- package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
- package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
- package/src/components/data-table/charts/charts.tsx +40 -30
- package/src/components/data-table/charts/storage.ts +16 -5
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-formatting/types.ts +1 -2
- package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
- package/src/components/data-table/column-summary/column-summary.tsx +2 -4
- package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
- package/src/components/data-table/columns.tsx +45 -46
- package/src/components/data-table/context-menu.tsx +36 -20
- package/src/components/data-table/data-table.tsx +17 -1
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +76 -48
- package/src/components/data-table/pagination.tsx +44 -33
- package/src/components/data-table/range-focus/atoms.ts +4 -6
- package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
- package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
- package/src/components/data-table/renderers.tsx +16 -7
- package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
- package/src/components/data-table/search-highlight.tsx +79 -0
- package/src/components/data-table/types.ts +1 -0
- package/src/components/data-table/url-detector.tsx +49 -9
- package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
- package/src/components/datasources/__tests__/column-preview.test.tsx +96 -5
- package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
- package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
- package/src/components/datasources/__tests__/utils.test.ts +57 -6
- package/src/components/datasources/column-preview.tsx +17 -12
- package/src/components/datasources/datasources.tsx +56 -43
- package/src/components/datasources/utils.ts +32 -23
- package/src/components/debugger/debugger-code.tsx +5 -0
- package/src/components/dependency-graph/custom-node.tsx +1 -1
- package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
- package/src/components/dependency-graph/elements.ts +24 -21
- package/src/components/dependency-graph/minimap-content.tsx +15 -20
- package/src/components/dependency-graph/panels.tsx +4 -2
- package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
- package/src/components/editor/SortableCell.tsx +1 -3
- package/src/components/editor/__tests__/Output.test.tsx +50 -32
- package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
- package/src/components/editor/__tests__/data-attributes.test.tsx +38 -26
- package/src/components/editor/__tests__/output-persistence.test.tsx +28 -9
- package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
- package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +21 -40
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +41 -14
- package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +6 -24
- package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +131 -0
- package/src/components/editor/actions/__tests__/useSetOutputsExpanded.test.ts +2 -1
- package/src/components/editor/actions/name-cell-input.tsx +4 -3
- package/src/components/editor/actions/pair-with-agent-commands.ts +10 -7
- package/src/components/editor/actions/pair-with-agent-modal.tsx +29 -30
- package/src/components/editor/actions/pair-with-agent.tsx +16 -39
- package/src/components/editor/actions/useCellActionButton.tsx +47 -35
- package/src/components/editor/actions/useConfigActions.tsx +3 -4
- package/src/components/editor/actions/useNotebookActions.tsx +25 -29
- package/src/components/editor/actions/useRestartKernel.tsx +0 -5
- package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
- package/src/components/editor/actions/useSetOutputsExpanded.ts +15 -23
- package/src/components/editor/ai/ai-completion-editor.tsx +2 -1
- package/src/components/editor/ai/completion-handlers.tsx +0 -37
- package/src/components/editor/ai/prompt-input.tsx +189 -0
- package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
- package/src/components/editor/alerts/connection-notice.tsx +1 -1
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/alerts/stdin-blocking-alert.tsx +4 -2
- package/src/components/editor/app-container.tsx +1 -1
- package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
- package/src/components/editor/cell/CellStatus.tsx +28 -23
- package/src/components/editor/cell/CreateCellButton.tsx +15 -21
- package/src/components/editor/cell/DeleteButton.tsx +3 -2
- package/src/components/editor/cell/RunButton.tsx +18 -8
- package/src/components/editor/cell/StagedAICell.tsx +52 -137
- package/src/components/editor/cell/StopButton.tsx +5 -5
- package/src/components/editor/cell/__tests__/useRunCells.test.tsx +151 -0
- package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
- package/src/components/editor/cell/cell-actions.tsx +12 -1
- package/src/components/editor/cell/cell-context-menu.tsx +22 -3
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +91 -0
- package/src/components/editor/cell/code/cell-editor.tsx +67 -170
- package/src/components/editor/cell/code/language-toggle.tsx +14 -11
- package/src/components/editor/cell/collapse.tsx +16 -6
- package/src/components/editor/cell/useAddCell.ts +4 -8
- package/src/components/editor/cell/useDeleteCell.tsx +10 -36
- package/src/components/editor/cell/useRunCells.ts +72 -58
- package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
- package/src/components/editor/cell/useSplitCell.tsx +10 -6
- package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
- package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
- package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
- package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
- package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
- package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
- package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
- package/src/components/editor/chrome/panels/panel-header.tsx +13 -0
- package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
- package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
- package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
- package/src/components/editor/chrome/types.ts +1 -1
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +7 -9
- package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +95 -0
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +265 -37
- package/src/components/editor/chrome/wrapper/__tests__/useAskAiAboutCell.test.tsx +58 -0
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +91 -74
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -17
- package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
- package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- package/src/components/editor/chrome/wrapper/footer.tsx +2 -2
- package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +143 -72
- package/src/components/editor/chrome/wrapper/pending-ai-changes-badge.tsx +25 -0
- package/src/components/editor/chrome/wrapper/sidebar.tsx +8 -4
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/chrome/wrapper/useAskAiAboutCell.ts +36 -0
- package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
- package/src/components/editor/columns/cell-column.tsx +1 -1
- package/src/components/editor/columns/sortable-column.tsx +2 -2
- package/src/components/editor/connections/components.tsx +5 -10
- package/src/components/editor/controls/Controls.tsx +4 -4
- package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
- package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +10 -4
- package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
- package/src/components/editor/documentation.css +34 -11
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +26 -22
- package/src/components/editor/errors/auto-fix.tsx +4 -8
- package/src/components/editor/errors/send-error-report-button.tsx +3 -6
- package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
- package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
- package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
- package/src/components/editor/file-tree/file-explorer.tsx +48 -15
- package/src/components/editor/file-tree/file-name-input.tsx +1 -0
- package/src/components/editor/file-tree/file-viewer.tsx +4 -2
- package/src/components/editor/file-tree/use-file-search.ts +35 -21
- package/src/components/editor/header/__tests__/filename-form.test.tsx +1 -4
- package/src/components/editor/header/__tests__/status.test.tsx +5 -3
- package/src/components/editor/header/app-header.tsx +1 -1
- package/src/components/editor/header/filename-form.tsx +1 -1
- package/src/components/editor/header/status.tsx +44 -22
- package/src/components/editor/links/__tests__/cell-link.test.tsx +148 -0
- package/src/components/editor/links/cell-link-list.tsx +1 -1
- package/src/components/editor/links/cell-link.tsx +21 -11
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
- package/src/components/editor/navigation/__tests__/navigation.test.ts +109 -85
- package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
- package/src/components/editor/navigation/clipboard.ts +17 -14
- package/src/components/editor/navigation/focus-utils.ts +23 -4
- package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
- package/src/components/editor/navigation/navigation.ts +74 -72
- package/src/components/editor/navigation/selection.ts +30 -29
- package/src/components/editor/notebook-banner.tsx +1 -0
- package/src/components/editor/notebook-cell.tsx +158 -172
- package/src/components/editor/output/MarimoErrorOutput.tsx +41 -4
- package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
- package/src/components/editor/output/Outputs.css +8 -0
- package/src/components/editor/output/VideoOutput.tsx +6 -0
- package/src/components/editor/output/__tests__/VideoOutput.test.tsx +131 -0
- package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
- package/src/components/editor/output/ansi-reduce.ts +40 -20
- package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
- package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
- package/src/components/editor/package-alert.tsx +14 -7
- package/src/components/editor/renderers/__tests__/add-cell-buttons.test.tsx +18 -0
- package/src/components/editor/renderers/cell-array.tsx +31 -102
- package/src/components/editor/renderers/grid-layout/__tests__/grid-layout.test.tsx +75 -0
- package/src/components/editor/renderers/grid-layout/grid-layout.tsx +28 -22
- package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -4
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
- package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
- package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
- package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +19 -37
- package/src/components/editor/stdin-blocking-alert.tsx +4 -2
- package/src/components/home/components.tsx +17 -31
- package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
- package/src/components/icons/large-spinner.tsx +3 -14
- package/src/components/icons/spinner.tsx +1 -1
- package/src/components/markdown/__tests__/markdown-renderer.test.tsx +32 -2
- package/src/components/markdown/markdown-renderer.tsx +43 -28
- package/src/components/mcp/mcp-status-indicator.tsx +18 -14
- package/src/components/pages/__tests__/home-page.test.tsx +116 -0
- package/src/components/pages/edit-page.tsx +19 -17
- package/src/components/pages/home-page.tsx +164 -91
- package/src/components/scratchpad/scratchpad.test.tsx +89 -0
- package/src/components/scratchpad/scratchpad.tsx +47 -33
- package/src/components/scratchpad/state.ts +7 -0
- package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
- package/src/components/slides/__tests__/minimap.test.ts +38 -19
- package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
- package/src/components/slides/minimap.tsx +22 -14
- package/src/components/slides/reveal-component.tsx +73 -36
- package/src/components/slides/reveal-slides.css +5 -4
- package/src/components/slides/slide-cell-view.tsx +39 -35
- package/src/components/slides/slide-form.tsx +1 -0
- package/src/components/slides/slide-scroll-hint.tsx +3 -1
- package/src/components/slides/slide.tsx +3 -4
- package/src/components/sort/SortableCellsProvider.tsx +8 -25
- package/src/components/static-html/__tests__/static-banner.test.tsx +1 -1
- package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
- package/src/components/tracing/tracing.tsx +46 -42
- package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
- package/src/components/ui/__tests__/fullscreen.test.tsx +99 -2
- package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
- package/src/components/ui/alert-dialog.tsx +1 -1
- package/src/components/ui/draggable-popover.tsx +24 -2
- package/src/components/ui/fullscreen.tsx +43 -3
- package/src/components/ui/range-slider.tsx +22 -9
- package/src/components/ui/slider.tsx +6 -2
- package/src/components/ui/toast.tsx +1 -1
- package/src/core/MarimoApp.tsx +3 -1
- package/src/core/ai/__tests__/staged-cells.test.ts +90 -609
- package/src/core/ai/context/context.ts +2 -0
- package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
- package/src/core/ai/context/providers/__tests__/cell.test.ts +49 -0
- package/src/core/ai/context/providers/cell-output.ts +2 -2
- package/src/core/ai/context/providers/cell.ts +54 -0
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/ai/staged-cells.ts +56 -323
- package/src/core/ai/state.ts +3 -0
- package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +47 -91
- package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
- package/src/core/ai/tools/base.ts +18 -15
- package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
- package/src/core/ai/tools/registry.ts +13 -10
- package/src/core/ai/tools/sample-tool.ts +6 -7
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +6 -529
- package/src/core/cells/__tests__/actions.test.ts +623 -35
- package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
- package/src/core/cells/__tests__/arrange.test.ts +432 -0
- package/src/core/cells/__tests__/cell.test.ts +148 -150
- package/src/core/cells/__tests__/cells.test.ts +384 -2930
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +69 -0
- package/src/core/cells/__tests__/document.test.ts +158 -0
- package/src/core/cells/__tests__/editor.test.ts +57 -0
- package/src/core/cells/__tests__/flush-document.test.ts +40 -0
- package/src/core/cells/__tests__/harness.ts +109 -0
- package/src/core/cells/__tests__/layout.test.ts +176 -0
- package/src/core/cells/__tests__/logs.test.ts +0 -13
- package/src/core/cells/__tests__/notebook-outline.test.ts +23 -14
- package/src/core/cells/__tests__/outputs.test.tsx +71 -53
- package/src/core/cells/__tests__/pending-delete-service.test.tsx +11 -20
- package/src/core/cells/__tests__/session.test.ts +546 -211
- package/src/core/cells/__tests__/utils.test.ts +135 -337
- package/src/core/cells/actions.ts +677 -6
- package/src/core/cells/add-missing-import.ts +48 -47
- package/src/core/cells/arrange.ts +529 -0
- package/src/core/cells/cell.ts +79 -146
- package/src/core/cells/cells.ts +106 -1459
- package/src/core/cells/columns.ts +38 -0
- package/src/core/cells/document.ts +167 -0
- package/src/core/cells/edit.ts +30 -0
- package/src/core/cells/editor.ts +82 -0
- package/src/core/cells/focus.ts +27 -6
- package/src/core/cells/layout.ts +221 -0
- package/src/core/cells/outputs.ts +12 -28
- package/src/core/cells/pending-delete-service.ts +8 -14
- package/src/core/cells/scrollCellIntoView.ts +6 -0
- package/src/core/cells/session.ts +166 -68
- package/src/core/cells/types.ts +21 -51
- package/src/core/cells/utils.ts +85 -87
- package/src/core/codemirror/__tests__/format.test.ts +4 -35
- package/src/core/codemirror/__tests__/setup.test.ts +67 -33
- package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
- package/src/core/codemirror/ai/resources.ts +1 -1
- package/src/core/codemirror/cells/__tests__/extensions.test.ts +2 -6
- package/src/core/codemirror/cells/extensions.ts +18 -30
- package/src/core/codemirror/cells/state.ts +2 -6
- package/src/core/codemirror/cm.ts +5 -1
- package/src/core/codemirror/config/types.ts +1 -1
- package/src/core/codemirror/copilot/__tests__/completion-integration.test.ts +4 -0
- package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +13 -10
- package/src/core/codemirror/copilot/getCodes.ts +3 -3
- package/src/core/codemirror/format.ts +6 -23
- package/src/core/codemirror/keymaps/vim.ts +4 -8
- package/src/core/codemirror/language/__tests__/extension.test.ts +7 -3
- package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
- package/src/core/codemirror/language/__tests__/utils.test.ts +194 -17
- package/src/core/codemirror/language/cell-code.ts +114 -0
- package/src/core/codemirror/language/extension.ts +52 -35
- package/src/core/codemirror/language/languages/markdown.ts +8 -6
- package/src/core/codemirror/language/languages/python.ts +19 -13
- package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/codemirror/language/types.ts +7 -7
- package/src/core/codemirror/language/utils.ts +9 -39
- package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
- package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
- package/src/core/codemirror/lsp/utils.ts +1 -1
- package/src/core/codemirror/misc/__tests__/paste.test.ts +3 -1
- package/src/core/codemirror/misc/paste.ts +1 -1
- package/src/core/codemirror/placeholder/__tests__/extensions.test.ts +75 -0
- package/src/core/codemirror/placeholder/extensions.ts +80 -19
- package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
- package/src/core/codemirror/readonly/extension.ts +2 -2
- package/src/core/codemirror/utils.ts +1 -0
- package/src/core/config/__tests__/app-config.test.ts +64 -0
- package/src/core/config/__tests__/config-schema.test.ts +177 -17
- package/src/core/config/config-schema.ts +116 -18
- package/src/core/config/config.ts +65 -20
- package/src/core/config/feature-flag.tsx +0 -2
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/documentation/doc-lookup.ts +1 -1
- package/src/core/dom/outline.ts +4 -1
- package/src/core/edit-app.tsx +28 -38
- package/src/core/errors/__tests__/error-entries.test.ts +40 -1
- package/src/core/errors/error-entries.ts +6 -4
- package/src/core/executions/__tests__/atoms.test.ts +282 -0
- package/src/core/executions/__tests__/freshness.test.ts +482 -0
- package/src/core/executions/__tests__/hooks.test.tsx +150 -0
- package/src/core/executions/__tests__/input.test.ts +86 -0
- package/src/core/executions/__tests__/interrupt.test.ts +200 -0
- package/src/core/executions/__tests__/output.test.ts +266 -0
- package/src/core/executions/__tests__/run.test.ts +387 -0
- package/src/core/executions/__tests__/select.test.ts +343 -0
- package/src/core/executions/atoms.ts +378 -0
- package/src/core/executions/freshness.ts +171 -0
- package/src/core/executions/hooks.ts +86 -0
- package/src/core/executions/index.ts +50 -0
- package/src/core/executions/input.ts +55 -0
- package/src/core/executions/interrupt.ts +49 -0
- package/src/core/executions/output.ts +242 -0
- package/src/core/executions/run.ts +107 -0
- package/src/core/executions/select.ts +210 -0
- package/src/core/export/__tests__/hooks.test.ts +0 -5
- package/src/core/export/hooks.ts +1 -1
- package/src/core/export/layout.ts +2 -2
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/hotkeys/hotkeys.ts +2 -1
- package/src/core/islands/__tests__/bootstrap.test.ts +69 -17
- package/src/core/islands/__tests__/bridge.test.ts +104 -65
- package/src/core/islands/bootstrap.ts +53 -55
- package/src/core/islands/bridge.ts +88 -43
- package/src/core/islands/components/IslandControls.tsx +15 -7
- package/src/core/islands/components/__tests__/IslandControls.test.tsx +36 -51
- package/src/core/islands/components/__tests__/web-components.test.tsx +63 -0
- package/src/core/islands/components/output-wrapper.tsx +5 -5
- package/src/core/islands/components/web-components.tsx +12 -1
- package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
- package/src/core/islands/worker/controller.ts +4 -10
- package/src/core/islands/worker/worker.tsx +78 -52
- package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
- package/src/core/kernel/__tests__/handlers.test.ts +7 -157
- package/src/core/kernel/handlers.ts +13 -79
- package/src/core/kernel/state.ts +0 -15
- package/src/core/lifecycle/render-policy.ts +12 -26
- package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
- package/src/core/meta/code-visibility.ts +18 -9
- package/src/core/network/__tests__/connection.test.ts +1 -1
- package/src/core/network/__tests__/requests-network.test.ts +0 -16
- package/src/core/network/__tests__/requests-toasting.test.tsx +7 -7
- package/src/core/network/connection-notice.ts +1 -1
- package/src/core/network/connection.ts +1 -6
- package/src/core/network/requests-network.ts +5 -55
- package/src/core/network/requests-static.ts +1 -7
- package/src/core/network/requests-toasting.tsx +2 -56
- package/src/core/network/resolve.ts +1 -5
- package/src/core/network/types.ts +6 -19
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/notebook/__tests__/operations.test.ts +51 -0
- package/src/core/notebook/attachments.ts +38 -0
- package/src/core/notebook/document/__tests__/codemirror.test.ts +765 -0
- package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
- package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
- package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
- package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
- package/src/core/notebook/document/__tests__/model.test.ts +247 -0
- package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
- package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
- package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
- package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
- package/src/core/notebook/document/__tests__/state.test.ts +459 -0
- package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
- package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
- package/src/core/notebook/document/__tests__/test-host.ts +243 -0
- package/src/core/notebook/document/__tests__/test-notebook.ts +150 -0
- package/src/core/notebook/document/__tests__/user.ts +61 -0
- package/src/core/notebook/document/codemirror.ts +216 -0
- package/src/core/notebook/document/draft.ts +502 -0
- package/src/core/notebook/document/hooks.tsx +118 -0
- package/src/core/notebook/document/index.ts +24 -0
- package/src/core/notebook/document/model.ts +102 -0
- package/src/core/notebook/document/select.ts +41 -0
- package/src/core/notebook/document/state.ts +378 -0
- package/src/core/notebook/document/sync.ts +376 -0
- package/src/core/notebook/index.ts +19 -0
- package/src/core/notebook/operations.ts +30 -0
- package/src/core/notebook/replica/AGENTS.md +11 -0
- package/src/core/{host → notebook/replica}/__tests__/attachments.test.ts +9 -10
- package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
- package/src/core/notebook/replica/__tests__/executions.test.ts +200 -0
- package/src/core/notebook/replica/__tests__/fixtures.ts +103 -0
- package/src/core/notebook/replica/__tests__/replica.test.ts +559 -0
- package/src/core/notebook/replica/__tests__/results.test.ts +193 -0
- package/src/core/notebook/replica/__tests__/runtime.test.ts +78 -0
- package/src/core/notebook/replica/backend.ts +21 -0
- package/src/core/notebook/replica/connection.ts +38 -0
- package/src/core/notebook/replica/index.ts +20 -0
- package/src/core/notebook/replica/replica.ts +336 -0
- package/src/core/{host → notebook/replica}/resources/attachments.ts +6 -3
- package/src/core/{host → notebook/replica}/resources/document.ts +3 -3
- package/src/core/notebook/replica/resources/executions.ts +157 -0
- package/src/core/notebook/replica/resources/results.ts +48 -0
- package/src/core/notebook/replica/resources/runtime.ts +14 -0
- package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
- package/src/core/packages/useSandboxController.ts +1 -1
- package/src/core/run-app.tsx +49 -51
- package/src/core/runtime/__tests__/adapter.test.ts +4 -4
- package/src/core/runtime/__tests__/createWsUrl.test.ts +70 -12
- package/src/core/runtime/__tests__/runtime.test.ts +82 -198
- package/src/core/runtime/adapter.ts +6 -13
- package/src/core/runtime/config.ts +4 -24
- package/src/core/runtime/runtime.ts +35 -58
- package/src/core/runtime/types.ts +0 -7
- package/src/core/saving/__tests__/document.test.tsx +123 -0
- package/src/core/saving/__tests__/state.test.ts +111 -0
- package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
- package/src/core/saving/document.ts +33 -0
- package/src/core/saving/filename.ts +1 -1
- package/src/core/saving/save-component.tsx +39 -60
- package/src/core/saving/state.ts +38 -39
- package/src/core/saving/useAutoSave.ts +17 -53
- package/src/core/session/__tests__/backend.test.ts +236 -0
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +186 -0
- package/src/core/{websocket → session}/__tests__/useNotebookSession.hook.test.tsx +354 -275
- package/src/core/session/active-notebook.ts +28 -0
- package/src/core/session/backend.ts +123 -0
- package/src/core/{websocket → session}/connection-utils.ts +2 -14
- package/src/core/session/embedded.ts +7 -0
- package/src/core/{websocket → session}/types.ts +2 -2
- package/src/core/session/useNotebookReplica.ts +74 -0
- package/src/core/{websocket → session}/useNotebookSession.tsx +97 -77
- package/src/core/state/__tests__/jotai.test.tsx +108 -0
- package/src/core/state/jotai.ts +1 -1
- package/src/core/static/__tests__/files.test.ts +38 -10
- package/src/core/static/files.ts +2 -0
- package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
- package/src/core/transports/__tests__/server.test.ts +408 -0
- package/src/core/transports/__tests__/static.test.ts +340 -0
- package/src/core/transports/__tests__/wasm.test.ts +166 -0
- package/src/core/{websocket → transports}/connection-state.ts +9 -16
- package/src/core/transports/server.ts +152 -0
- package/src/core/transports/static.ts +180 -0
- package/src/core/transports/wasm.ts +95 -0
- package/src/core/vscode/__tests__/vscode-bindings.test.ts +125 -0
- package/src/core/vscode/vscode-bindings.ts +14 -2
- package/src/core/wasm/__tests__/bridge.test.ts +354 -64
- package/src/core/wasm/__tests__/worker.test.ts +191 -0
- package/src/core/wasm/bridge.ts +167 -92
- package/src/core/wasm/rpc.ts +15 -3
- package/src/core/wasm/store.ts +3 -3
- package/src/core/wasm/worker/bootstrap.ts +55 -51
- package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
- package/src/core/wasm/worker/save-worker.ts +9 -10
- package/src/core/wasm/worker/types.ts +31 -19
- package/src/core/wasm/worker/worker.ts +120 -72
- package/src/css/app/Cell.css +7 -36
- package/src/css/app/codemirror.css +1 -1
- package/src/css/common.css +1 -1
- package/src/css/globals.css +72 -24
- package/src/css/katex.min.css +1 -1
- package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
- package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
- package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
- package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
- package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
- package/src/hooks/__tests__/useScript.test.tsx +77 -0
- package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
- package/src/hooks/useAsyncData.ts +3 -3
- package/src/hooks/useDataSourceDiscovery.ts +6 -4
- package/src/hooks/useDebounce.ts +6 -10
- package/src/hooks/useDeepCompareMemoize.ts +1 -1
- package/src/hooks/useDelayElapsed.ts +14 -10
- package/src/hooks/useElapsedTime.ts +3 -3
- package/src/hooks/useEventListener.ts +1 -2
- package/src/hooks/useInputHistory.ts +4 -7
- package/src/hooks/useInternalStateWithSync.ts +6 -6
- package/src/hooks/useResizeObserver.ts +4 -7
- package/src/hooks/useScript.ts +67 -70
- package/src/hooks/useStateForKey.ts +93 -0
- package/src/mount.tsx +22 -23
- package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
- package/src/plugins/core/RenderHTML.tsx +3 -5
- package/src/plugins/core/__test__/PluginSlot.test.tsx +202 -0
- package/src/plugins/core/__test__/RenderHTML-copy.test.tsx +60 -0
- package/src/plugins/core/__test__/registerReactComponent.test.ts +45 -0
- package/src/plugins/core/__test__/sanitize.test.ts +8 -0
- package/src/plugins/core/registerReactComponent.tsx +29 -29
- package/src/plugins/core/sanitize-html.ts +6 -0
- package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataEditorPlugin.tsx +60 -28
- package/src/plugins/impl/DataTablePlugin.tsx +69 -37
- package/src/plugins/impl/DropdownPlugin.tsx +2 -6
- package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
- package/src/plugins/impl/FormPlugin.tsx +1 -1
- package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
- package/src/plugins/impl/RefreshPlugin.tsx +1 -0
- package/src/plugins/impl/SliderPlugin.tsx +41 -11
- package/src/plugins/impl/__test__/slider-labels.test.tsx +30 -0
- package/src/plugins/impl/__tests__/DataEditorPlugin.test.ts +190 -10
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
- package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
- package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +64 -3
- package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/model.ts +3 -1
- package/src/plugins/impl/anywidget/registry.ts +18 -14
- package/src/plugins/impl/anywidget/runtime.ts +21 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
- package/src/plugins/impl/chat/chat-ui.tsx +17 -15
- package/src/plugins/impl/code/any-language-editor.tsx +2 -2
- package/src/plugins/impl/common/error-banner.tsx +5 -3
- package/src/plugins/impl/data-editor/__tests__/column-types.test.ts +42 -0
- package/src/plugins/impl/data-editor/__tests__/editor-state.test.ts +52 -1
- package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +278 -7
- package/src/plugins/impl/data-editor/__tests__/glide-utils.test.ts +116 -0
- package/src/plugins/impl/data-editor/column-types.ts +55 -0
- package/src/plugins/impl/data-editor/editor-state.ts +18 -2
- package/src/plugins/impl/data-editor/glide-data-editor.tsx +104 -22
- package/src/plugins/impl/data-editor/glide-portal.tsx +5 -3
- package/src/plugins/impl/data-editor/glide-utils.ts +39 -38
- package/src/plugins/impl/data-editor/types.ts +5 -0
- package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
- package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
- package/src/plugins/impl/data-explorer/functions/types.ts +1 -5
- package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
- package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
- package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
- package/src/plugins/impl/data-frames/panel.tsx +44 -16
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
- package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
- package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
- package/src/plugins/impl/panel/utils.ts +17 -0
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
- package/src/plugins/impl/plotly/selection.ts +25 -19
- package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
- package/src/plugins/impl/vega/make-selectable.ts +4 -7
- package/src/plugins/layout/AccordionPlugin.tsx +2 -1
- package/src/plugins/layout/DownloadPlugin.tsx +7 -11
- package/src/plugins/layout/LazyPlugin.tsx +7 -4
- package/src/plugins/layout/RoutesPlugin.tsx +1 -1
- package/src/plugins/layout/TexPlugin.tsx +0 -1
- package/src/plugins/layout/__test__/DownloadPlugin.test.tsx +205 -0
- package/src/plugins/layout/__tests__/AccordionPlugin.test.tsx +21 -0
- package/src/plugins/layout/__tests__/LazyPlugin.test.tsx +98 -0
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/button.stories.tsx +1 -0
- package/src/stories/cell-status.stories.tsx +29 -24
- package/src/stories/cell.stories.tsx +46 -46
- package/src/stories/data-table.stories.tsx +31 -0
- package/src/stories/editor.stories.tsx +28 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- package/src/stories/layout/vertical/one-column.stories.tsx +28 -42
- package/src/stories/runtime-story.tsx +23 -17
- package/src/stories/select.stories.tsx +2 -2
- package/src/stories/switchable-multi-select.stories.tsx +1 -1
- package/src/stories/theme.stories.tsx +4 -1
- package/src/theme/__tests__/islands-theme.test.tsx +276 -0
- package/src/theme/namespace.tsx +4 -3
- package/src/theme/useTheme.ts +71 -41
- package/src/utils/__tests__/arrays.test.ts +35 -0
- package/src/utils/__tests__/batch-requests.test.ts +3 -3
- package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +127 -1
- package/src/utils/__tests__/download.test.tsx +183 -23
- package/src/utils/__tests__/numbers.test.ts +105 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +11 -2
- package/src/utils/blob.ts +1 -1
- package/src/utils/createReducer.ts +115 -79
- package/src/utils/download.ts +67 -6
- package/src/utils/errors.ts +0 -7
- package/src/utils/maps.ts +0 -3
- package/src/utils/numbers.ts +79 -18
- package/src/utils/objects.ts +4 -9
- package/src/utils/time.ts +10 -0
- package/src/utils/tracer.ts +9 -5
- package/src/utils/zod-utils.ts +1 -3
- package/dist/_baseMerge-BiGRwuqv.js +0 -165
- package/dist/any-language-editor-D4q-IFcM.js +0 -76
- package/dist/architecture-7GRP2DOG-BWLylgiA.js +0 -3
- package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
- package/dist/assets/worker-HPY9fbhz.js +0 -114
- package/dist/classDiagram-ZZMXUADV-DXdCCDOg.js +0 -30
- package/dist/classDiagram-v2-VYDZK3BY-DyZqrtLP.js +0 -30
- package/dist/code-visibility-A6NQ-XVM.js +0 -138
- package/dist/cynefin-OW5HDTMX-obq-i80l.js +0 -3
- package/dist/dropdown-menu-BuE2b8Yb.js +0 -4678
- package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +0 -3
- package/dist/flowDiagram-HODETNUW-DQ4JuadE.js +0 -16
- package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +0 -3
- package/dist/hasIn-o2Us0uVx.js +0 -132
- package/dist/highlighted-body-KPVGNVTW-3Ziwfz-V.js +0 -38
- package/dist/html-to-image-BsG_zyNW.js +0 -3251
- package/dist/info-A6RAGUB7-DKoayiHY.js +0 -3
- package/dist/isArrayLikeObject-BZl-15ir.js +0 -450
- package/dist/isEmpty-BSZ1LaUo.js +0 -35
- package/dist/isSymbol-kQcfYbNX.js +0 -8
- package/dist/label-DoysmLMW.js +0 -281
- package/dist/linear-DWERh7eI.js +0 -252
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +0 -2
- package/dist/packet-AYTQ26CC-Yw7ajchJ.js +0 -3
- package/dist/pick-CJeoxYOS.js +0 -51
- package/dist/pie-WAS4IAKB-BKdKOAkL.js +0 -3
- package/dist/precisionRound-DhAzeRcm.js +0 -49
- package/dist/purify.es-DMv5zIkJ.js +0 -866
- package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +0 -3
- package/dist/railroad-74A4TZTK-DQvPSdo5.js +0 -3
- package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +0 -3
- package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +0 -3
- package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +0 -3
- package/dist/select-DemoKT4G.js +0 -1344
- package/dist/stateDiagram-v2-MP3YSRHH-1OQRe6iA.js +0 -30
- package/dist/swimlanesDiagram-VR7AAH4N-CszjkrKo.js +0 -30
- package/dist/toDate-gyi35XS2.js +0 -1185
- package/dist/toast-PkdZraM8.js +0 -1830
- package/dist/treeView-Q6P3EWNA-DuRV97YF.js +0 -3
- package/dist/treemap-WGGIJYW6-AsLq-uwC.js +0 -3
- package/dist/use-restore-focus-CKjfFjLM.js +0 -6369
- package/dist/useLifecycle-Dfq8UD-b.js +0 -169
- package/dist/useTheme-Bu5bBgrh.js +0 -904
- package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +0 -3
- package/src/components/chat/reasoning-accordion.tsx +0 -61
- package/src/components/chat/tool-call/tool-error-card.tsx +0 -81
- package/src/components/chat/tool-call/tool-history-row.tsx +0 -174
- package/src/components/editor/ai/__tests__/staged-cell-submission.test.ts +0 -106
- package/src/components/editor/ai/add-cell-with-ai.tsx +0 -506
- package/src/components/editor/ai/staged-cell-submission.ts +0 -46
- package/src/components/editor/alerts/connecting-alert.tsx +0 -27
- package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +0 -64
- package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
- package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
- package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
- package/src/components/editor/navigation/state.ts +0 -65
- package/src/components/icons/loading-ellipsis.tsx +0 -46
- package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
- package/src/core/ai/tools/run-cells-tool.ts +0 -303
- package/src/core/attachments/state.ts +0 -18
- package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
- package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
- package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
- package/src/core/cells/document-changes.ts +0 -944
- package/src/core/codemirror/rtc/extension.ts +0 -453
- package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
- package/src/core/codemirror/rtc/loro/awareness.ts +0 -531
- package/src/core/codemirror/rtc/loro/colors.ts +0 -38
- package/src/core/codemirror/rtc/loro/sync.ts +0 -168
- package/src/core/host/AGENTS.md +0 -11
- package/src/core/host/__tests__/events.test.ts +0 -46
- package/src/core/host/__tests__/fixtures.ts +0 -39
- package/src/core/host/__tests__/notebook-client.test.ts +0 -433
- package/src/core/host/__tests__/protocol.test.ts +0 -229
- package/src/core/host/__tests__/stream.test.ts +0 -209
- package/src/core/host/connection.ts +0 -81
- package/src/core/host/events.ts +0 -61
- package/src/core/host/notebook-client.ts +0 -290
- package/src/core/host/protocol.ts +0 -1948
- package/src/core/host/resources/resource.ts +0 -47
- package/src/core/host/stream.ts +0 -211
- package/src/core/network/__tests__/requests-lazy.test.ts +0 -334
- package/src/core/network/requests-lazy.ts +0 -226
- package/src/core/rtc/state.ts +0 -34
- package/src/core/state/__tests__/jotai.test.ts +0 -25
- package/src/core/wasm/worker/message-buffer.ts +0 -33
- package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -170
- package/src/core/websocket/state.ts +0 -7
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/create.ts +0 -31
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -50
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useNotebookClient.ts +0 -88
- package/src/utils/__tests__/id-tree.test.ts +0 -2145
- package/src/utils/id-tree.tsx +0 -1134
- /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import { defaultUserConfig } from "@/core/config/config-schema";
|
|
4
|
+
|
|
3
5
|
import { python } from "@codemirror/lang-python";
|
|
4
6
|
import { EditorState } from "@codemirror/state";
|
|
5
7
|
import { EditorView } from "@codemirror/view";
|
|
6
8
|
import { createStore } from "jotai";
|
|
9
|
+
import { createRef } from "react";
|
|
7
10
|
import {
|
|
8
11
|
afterAll,
|
|
9
|
-
afterEach,
|
|
10
12
|
beforeAll,
|
|
13
|
+
afterEach,
|
|
11
14
|
beforeEach,
|
|
12
15
|
describe,
|
|
13
16
|
expect,
|
|
14
17
|
it,
|
|
15
18
|
vi,
|
|
16
19
|
} from "vitest";
|
|
20
|
+
import { MockExecutions } from "@/__mocks__/executions";
|
|
17
21
|
import { MockNotebook } from "@/__mocks__/notebook";
|
|
18
22
|
import { cellId } from "@/__tests__/branded";
|
|
19
23
|
import type { CellHandle } from "@/components/editor/notebook-cell";
|
|
20
|
-
import { CellId, SCRATCH_CELL_ID
|
|
24
|
+
import { CellId, SCRATCH_CELL_ID } from "@/core/cells/ids";
|
|
21
25
|
import { foldAllBulk, unfoldAllBulk } from "@/core/codemirror/editing/commands";
|
|
22
26
|
import { adaptiveLanguageConfiguration } from "@/core/codemirror/language/extension";
|
|
23
27
|
import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
|
|
24
28
|
import type { OutputMessage } from "@/core/kernel/messages";
|
|
25
|
-
import {
|
|
26
|
-
type CollapsibleTree,
|
|
27
|
-
MultiColumn,
|
|
28
|
-
type CellColumnId,
|
|
29
|
-
} from "@/utils/id-tree";
|
|
29
|
+
import type { CellConfig } from "@/core/network/types";
|
|
30
30
|
import type { Seconds } from "@/utils/time";
|
|
31
31
|
import {
|
|
32
32
|
exportedForTesting,
|
|
@@ -34,13 +34,12 @@ import {
|
|
|
34
34
|
type NotebookState,
|
|
35
35
|
notebookAtom,
|
|
36
36
|
} from "../cells";
|
|
37
|
-
import { exportedForTesting as documentTransactionTestExports } from "../document-changes";
|
|
38
37
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
type CellData,
|
|
39
|
+
createCell,
|
|
40
|
+
createCellConfig,
|
|
41
|
+
createCellRuntimeState,
|
|
42
|
+
} from "../types";
|
|
44
43
|
|
|
45
44
|
vi.mock("@/core/codemirror/editing/commands", () => ({
|
|
46
45
|
foldAllBulk: vi.fn(),
|
|
@@ -60,9 +59,6 @@ vi.mock("../scrollCellIntoView", async (importOriginal) => {
|
|
|
60
59
|
};
|
|
61
60
|
});
|
|
62
61
|
|
|
63
|
-
const FIRST_COLUMN = 0;
|
|
64
|
-
const SECOND_COLUMN = 1;
|
|
65
|
-
|
|
66
62
|
const { initialNotebookState, reducer, createActions } = exportedForTesting;
|
|
67
63
|
|
|
68
64
|
function formatCells(notebook: NotebookState) {
|
|
@@ -78,14 +74,7 @@ function formatCells(notebook: NotebookState) {
|
|
|
78
74
|
const cells = cellsId.map((cellId) => cellData[cellId]);
|
|
79
75
|
return cells.map((cell) => printCell(cell)).join("\n\n");
|
|
80
76
|
};
|
|
81
|
-
|
|
82
|
-
return `> col ${columnIdx}\n${printCells(column.inOrderIds)}`;
|
|
83
|
-
};
|
|
84
|
-
const columns = cellIds.getColumns();
|
|
85
|
-
if (columns.length > 1) {
|
|
86
|
-
return wrap(columns.map(printColumn).join("\n\n"));
|
|
87
|
-
}
|
|
88
|
-
return wrap(printCells(cellIds.inOrderIds));
|
|
77
|
+
return wrap(printCells(cellIds));
|
|
89
78
|
}
|
|
90
79
|
|
|
91
80
|
function createEditor(content: string) {
|
|
@@ -96,6 +85,7 @@ function createEditor(content: string) {
|
|
|
96
85
|
adaptiveLanguageConfiguration({
|
|
97
86
|
cellId: cellId("cell1"),
|
|
98
87
|
completionConfig: {
|
|
88
|
+
...defaultUserConfig().completion,
|
|
99
89
|
activate_on_typing: true,
|
|
100
90
|
signature_hint_on_typing: false,
|
|
101
91
|
copilot: false,
|
|
@@ -103,7 +93,7 @@ function createEditor(content: string) {
|
|
|
103
93
|
},
|
|
104
94
|
hotkeys: new OverridingHotkeyProvider({}),
|
|
105
95
|
placeholderType: "marimo-import",
|
|
106
|
-
lspConfig: {},
|
|
96
|
+
lspConfig: { ...defaultUserConfig().language_servers },
|
|
107
97
|
}),
|
|
108
98
|
],
|
|
109
99
|
});
|
|
@@ -121,8 +111,7 @@ describe("cell reducer", () => {
|
|
|
121
111
|
let cells: ReturnType<typeof flattenTopLevelNotebookCells>;
|
|
122
112
|
let firstCellId: CellId;
|
|
123
113
|
|
|
124
|
-
const
|
|
125
|
-
state = reducer(state, action);
|
|
114
|
+
const mountEditors = () => {
|
|
126
115
|
for (const [cellIdString, handle] of Object.entries(state.cellHandles)) {
|
|
127
116
|
// @ts-expect-error - Typescript Object.entries doesn't know that keys are CellId
|
|
128
117
|
const cid: CellId = cellIdString;
|
|
@@ -136,7 +125,83 @@ describe("cell reducer", () => {
|
|
|
136
125
|
}
|
|
137
126
|
}
|
|
138
127
|
cells = flattenTopLevelNotebookCells(state);
|
|
139
|
-
}
|
|
128
|
+
};
|
|
129
|
+
const actions = createActions((action) => {
|
|
130
|
+
state = reducer(state, action);
|
|
131
|
+
mountEditors();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/** Put a cell into the notebook the way the document would. */
|
|
135
|
+
function seedCell({
|
|
136
|
+
cellId,
|
|
137
|
+
before,
|
|
138
|
+
code = "",
|
|
139
|
+
name,
|
|
140
|
+
config,
|
|
141
|
+
newCellId,
|
|
142
|
+
hideCode,
|
|
143
|
+
autoFocus = true,
|
|
144
|
+
}: {
|
|
145
|
+
cellId: CellId | "__end__";
|
|
146
|
+
before: boolean;
|
|
147
|
+
code?: string;
|
|
148
|
+
name?: string;
|
|
149
|
+
config?: CellConfig;
|
|
150
|
+
newCellId?: CellId;
|
|
151
|
+
hideCode?: boolean;
|
|
152
|
+
autoFocus?: boolean;
|
|
153
|
+
}): CellId {
|
|
154
|
+
const cellIndex =
|
|
155
|
+
cellId === "__end__"
|
|
156
|
+
? state.cellIds.length
|
|
157
|
+
: state.cellIds.indexOf(cellId);
|
|
158
|
+
const id = newCellId ?? CellId.create();
|
|
159
|
+
const cellIds = [...state.cellIds];
|
|
160
|
+
cellIds.splice(before ? cellIndex : cellIndex + 1, 0, id);
|
|
161
|
+
state = {
|
|
162
|
+
...state,
|
|
163
|
+
cellIds,
|
|
164
|
+
cellData: {
|
|
165
|
+
...state.cellData,
|
|
166
|
+
[id]: createCell({
|
|
167
|
+
id,
|
|
168
|
+
code,
|
|
169
|
+
name,
|
|
170
|
+
config: createCellConfig({
|
|
171
|
+
...config,
|
|
172
|
+
...(hideCode != null && { hide_code: hideCode }),
|
|
173
|
+
}),
|
|
174
|
+
}),
|
|
175
|
+
},
|
|
176
|
+
cellRuntime: { ...state.cellRuntime, [id]: createCellRuntimeState() },
|
|
177
|
+
cellHandles: { ...state.cellHandles, [id]: createRef() },
|
|
178
|
+
scrollKey: autoFocus ? id : null,
|
|
179
|
+
};
|
|
180
|
+
mountEditors();
|
|
181
|
+
return id;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Edit a cell's code as the document delivers it. */
|
|
185
|
+
function editCode(cellId: CellId, code: string) {
|
|
186
|
+
const cells = state.cellIds.map((id) => {
|
|
187
|
+
const cell = state.cellData[id];
|
|
188
|
+
return {
|
|
189
|
+
id,
|
|
190
|
+
code: id === cellId ? code : cell.code,
|
|
191
|
+
name: cell.name,
|
|
192
|
+
config: {
|
|
193
|
+
column: cell.config.column ?? null,
|
|
194
|
+
disabled: cell.config.disabled ?? false,
|
|
195
|
+
hide_code: cell.config.hide_code ?? false,
|
|
196
|
+
expand_output: cell.config.expand_output ?? false,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
actions.reconcileDocument({
|
|
201
|
+
order: state.cellIds,
|
|
202
|
+
cells: new Map(cells.map((cell) => [cell.id, cell])),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
140
205
|
|
|
141
206
|
let i = 0;
|
|
142
207
|
const originalCreate = CellId.create.bind(CellId);
|
|
@@ -151,907 +216,214 @@ describe("cell reducer", () => {
|
|
|
151
216
|
i = 0;
|
|
152
217
|
|
|
153
218
|
state = initialNotebookState();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
firstCellId = state.cellIds.inOrderIds[0];
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
afterEach(() => {
|
|
160
|
-
documentTransactionTestExports.cancelPendingChanges();
|
|
219
|
+
seedCell({ cellId: "__end__", before: false });
|
|
220
|
+
firstCellId = state.cellIds[0];
|
|
161
221
|
});
|
|
162
222
|
|
|
163
223
|
afterAll(() => {
|
|
164
224
|
CellId.create = originalCreate;
|
|
165
225
|
});
|
|
166
226
|
|
|
167
|
-
it("can
|
|
168
|
-
|
|
169
|
-
cellId: firstCellId,
|
|
170
|
-
before: false,
|
|
171
|
-
});
|
|
227
|
+
it("can update a cell", () => {
|
|
228
|
+
editCode(firstCellId, "import numpy as np");
|
|
172
229
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
173
230
|
"
|
|
174
|
-
[0] ''
|
|
175
|
-
|
|
176
|
-
[1] ''
|
|
231
|
+
[0] 'import numpy as np'
|
|
177
232
|
"
|
|
178
233
|
`);
|
|
179
234
|
});
|
|
180
235
|
|
|
181
|
-
it("
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
236
|
+
it("keeps error evidence after an edit and a new queued run", () => {
|
|
237
|
+
const code = "raise ValueError('old failure')";
|
|
238
|
+
const output: OutputMessage = {
|
|
239
|
+
channel: "marimo-error",
|
|
240
|
+
mimetype: "application/vnd.marimo+error",
|
|
241
|
+
data: [
|
|
242
|
+
{
|
|
243
|
+
type: "exception",
|
|
244
|
+
msg: "old failure",
|
|
245
|
+
exception_type: "ValueError",
|
|
246
|
+
raising_cell: null,
|
|
247
|
+
traceback: "<pre>ValueError: old failure</pre>",
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
code,
|
|
251
|
+
timestamp: 1,
|
|
252
|
+
};
|
|
253
|
+
actions.handleCellMessage({
|
|
254
|
+
cell_id: firstCellId,
|
|
255
|
+
output,
|
|
256
|
+
console: {
|
|
257
|
+
channel: "stderr",
|
|
258
|
+
mimetype: "application/vnd.marimo+traceback",
|
|
259
|
+
data: "<pre>ValueError: old failure</pre>",
|
|
260
|
+
code,
|
|
261
|
+
timestamp: 1,
|
|
262
|
+
},
|
|
263
|
+
status: "idle",
|
|
264
|
+
timestamp: 1,
|
|
186
265
|
});
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
266
|
+
editCode(firstCellId, "print('new code')");
|
|
267
|
+
actions.prepareForRun({ cellId: firstCellId });
|
|
268
|
+
actions.handleCellMessage({
|
|
269
|
+
cell_id: firstCellId,
|
|
270
|
+
output: null,
|
|
271
|
+
console: null,
|
|
272
|
+
status: "queued",
|
|
273
|
+
timestamp: 2,
|
|
274
|
+
});
|
|
275
|
+
const runtime = state.cellRuntime[firstCellId];
|
|
276
|
+
expect(runtime.output).toEqual(output);
|
|
277
|
+
expect(runtime.consoleOutputs[0].code).toBe(code);
|
|
278
|
+
expect(runtime.consoleOutputs[0].data).toContain("old failure");
|
|
279
|
+
});
|
|
190
280
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
281
|
+
it("can run cell and receive cell messages", () => {
|
|
282
|
+
// HAPPY PATH
|
|
283
|
+
/////////////////
|
|
284
|
+
// Initial state
|
|
285
|
+
let cell = cells[0];
|
|
286
|
+
expect(cell).toMatchSnapshot("initial state");
|
|
194
287
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
expect(
|
|
199
|
-
});
|
|
288
|
+
// Update code
|
|
289
|
+
editCode(firstCellId, "import marimo as mo");
|
|
290
|
+
cell = cells[0];
|
|
291
|
+
expect(cell).toMatchSnapshot("code edited");
|
|
200
292
|
|
|
201
|
-
|
|
202
|
-
actions.
|
|
293
|
+
// Prepare for run
|
|
294
|
+
actions.prepareForRun({
|
|
203
295
|
cellId: firstCellId,
|
|
204
|
-
before: true,
|
|
205
296
|
});
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
[1] ''
|
|
297
|
+
cell = cells[0];
|
|
298
|
+
expect(cell).toMatchSnapshot("prepared for run");
|
|
209
299
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
300
|
+
// Receive queued messages
|
|
301
|
+
actions.handleCellMessage({
|
|
302
|
+
cell_id: firstCellId,
|
|
303
|
+
output: undefined,
|
|
304
|
+
console: null,
|
|
305
|
+
status: "queued",
|
|
306
|
+
timestamp: new Date(10).getTime() as Seconds,
|
|
307
|
+
});
|
|
308
|
+
cell = cells[0];
|
|
309
|
+
expect(cell).toMatchSnapshot("queued message received");
|
|
214
310
|
|
|
215
|
-
|
|
216
|
-
actions.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
311
|
+
// Receive running messages
|
|
312
|
+
actions.handleCellMessage({
|
|
313
|
+
cell_id: firstCellId,
|
|
314
|
+
output: undefined,
|
|
315
|
+
console: null,
|
|
316
|
+
status: "running",
|
|
317
|
+
timestamp: new Date(20).getTime() as Seconds,
|
|
222
318
|
});
|
|
223
|
-
|
|
224
|
-
expect(
|
|
225
|
-
expect(state.cellData[newCellId].config.hide_code).toBe(true);
|
|
226
|
-
expect(state.cellData[newCellId].config.disabled).toBe(false);
|
|
227
|
-
});
|
|
319
|
+
cell = cells[0];
|
|
320
|
+
expect(cell).toMatchSnapshot("running message received");
|
|
228
321
|
|
|
229
|
-
|
|
230
|
-
actions.
|
|
231
|
-
|
|
232
|
-
|
|
322
|
+
// Console messages shouldn't transition status
|
|
323
|
+
actions.handleCellMessage({
|
|
324
|
+
cell_id: firstCellId,
|
|
325
|
+
output: undefined,
|
|
326
|
+
console: {
|
|
327
|
+
channel: "stdout",
|
|
328
|
+
mimetype: "text/plain",
|
|
329
|
+
data: "hello!",
|
|
330
|
+
timestamp: 0,
|
|
331
|
+
},
|
|
332
|
+
status: undefined,
|
|
333
|
+
timestamp: new Date(22).getTime() as Seconds,
|
|
233
334
|
});
|
|
234
|
-
|
|
235
|
-
|
|
335
|
+
cell = cells[0];
|
|
336
|
+
expect(cell).toMatchSnapshot("console message received");
|
|
337
|
+
|
|
338
|
+
// Receive output messages
|
|
339
|
+
actions.handleCellMessage({
|
|
340
|
+
cell_id: firstCellId,
|
|
341
|
+
output: {
|
|
342
|
+
channel: "output",
|
|
343
|
+
mimetype: "text/plain",
|
|
344
|
+
data: "ok",
|
|
345
|
+
timestamp: 0,
|
|
346
|
+
},
|
|
347
|
+
console: {
|
|
348
|
+
channel: "stdout",
|
|
349
|
+
mimetype: "text/plain",
|
|
350
|
+
data: "hello!",
|
|
351
|
+
timestamp: 0,
|
|
352
|
+
},
|
|
353
|
+
status: "idle",
|
|
354
|
+
timestamp: new Date(33).getTime() as Seconds,
|
|
236
355
|
});
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
[1] ''
|
|
240
|
-
"
|
|
241
|
-
`);
|
|
356
|
+
cell = cells[0];
|
|
357
|
+
expect(cell).toMatchSnapshot("output received");
|
|
242
358
|
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
359
|
+
// EDITING BACK AND FORTH
|
|
360
|
+
/////////////////
|
|
361
|
+
// Update code again
|
|
362
|
+
editCode(firstCellId, "import marimo as mo\nimport numpy");
|
|
363
|
+
cell = cells[0];
|
|
364
|
+
expect(cell).toMatchSnapshot("code edited again");
|
|
248
365
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
366
|
+
// Update code should be unedited
|
|
367
|
+
editCode(firstCellId, "import marimo as mo");
|
|
368
|
+
cell = cells[0];
|
|
369
|
+
expect(cell).toMatchSnapshot("code reverted");
|
|
252
370
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
371
|
+
// Update code should be edited again
|
|
372
|
+
editCode(firstCellId, "import marimo as mo\nimport numpy");
|
|
373
|
+
cell = cells[0];
|
|
374
|
+
expect(cell).toMatchSnapshot("code changed after revert");
|
|
256
375
|
|
|
257
|
-
|
|
258
|
-
|
|
376
|
+
// ERROR RESPONSE
|
|
377
|
+
/////////////////
|
|
378
|
+
// Prepare for run
|
|
379
|
+
actions.prepareForRun({
|
|
259
380
|
cellId: firstCellId,
|
|
260
|
-
before: false,
|
|
261
|
-
code: `df = mo.sql("""SELECT * FROM table""")`,
|
|
262
381
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
382
|
+
cell = cells[0];
|
|
383
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
384
|
+
// Queue
|
|
385
|
+
actions.handleCellMessage({
|
|
386
|
+
cell_id: firstCellId,
|
|
387
|
+
output: undefined,
|
|
388
|
+
console: null,
|
|
389
|
+
status: "queued",
|
|
390
|
+
timestamp: new Date(40).getTime() as Seconds,
|
|
266
391
|
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
"
|
|
277
|
-
[0] ''
|
|
278
|
-
|
|
279
|
-
[2] 'df = mo.sql("""SELECT * FROM table""")'
|
|
280
|
-
"
|
|
281
|
-
`);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("can delete a Markdown cell and undo delete", () => {
|
|
285
|
-
const text = "The quick brown fox jumps over the lazy dog.";
|
|
286
|
-
actions.createNewCell({
|
|
287
|
-
cellId: firstCellId,
|
|
288
|
-
before: false,
|
|
289
|
-
code: `mo.md(r"""${text}""")`,
|
|
392
|
+
cell = cells[0];
|
|
393
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
394
|
+
// Running
|
|
395
|
+
actions.handleCellMessage({
|
|
396
|
+
cell_id: firstCellId,
|
|
397
|
+
output: undefined,
|
|
398
|
+
console: null,
|
|
399
|
+
status: "running",
|
|
400
|
+
timestamp: new Date(50).getTime() as Seconds,
|
|
290
401
|
});
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
402
|
+
cell = cells[0];
|
|
403
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
404
|
+
// Receive error
|
|
405
|
+
actions.handleCellMessage({
|
|
406
|
+
cell_id: firstCellId,
|
|
407
|
+
output: {
|
|
408
|
+
channel: "marimo-error",
|
|
409
|
+
mimetype: "application/vnd.marimo+error",
|
|
410
|
+
data: [
|
|
411
|
+
{ type: "exception", exception_type: "ValueError", msg: "Oh no!" },
|
|
412
|
+
],
|
|
413
|
+
timestamp: 0,
|
|
414
|
+
},
|
|
415
|
+
console: null,
|
|
416
|
+
status: "idle",
|
|
417
|
+
timestamp: new Date(61).getTime() as Seconds,
|
|
294
418
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
"
|
|
299
|
-
`);
|
|
300
|
-
|
|
301
|
-
// undo
|
|
302
|
-
actions.undoDeleteCell();
|
|
303
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
304
|
-
"
|
|
305
|
-
[0] ''
|
|
306
|
-
|
|
307
|
-
[2] 'mo.md(r"""The quick brown fox jumps over the lazy dog.""")'
|
|
308
|
-
"
|
|
309
|
-
`);
|
|
310
|
-
});
|
|
419
|
+
cell = cells[0];
|
|
420
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
421
|
+
expect(cell).toMatchSnapshot("error response received");
|
|
311
422
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
code: "x = 1",
|
|
317
|
-
});
|
|
318
|
-
const newCellId = state.cellIds.getColumns()[0].atOrThrow(1);
|
|
319
|
-
|
|
320
|
-
// Set config to hidden and disabled
|
|
321
|
-
actions.updateCellConfig({
|
|
322
|
-
cellId: newCellId,
|
|
323
|
-
config: { hide_code: true, disabled: true },
|
|
324
|
-
});
|
|
325
|
-
expect(state.cellData[newCellId].config.hide_code).toBe(true);
|
|
326
|
-
expect(state.cellData[newCellId].config.disabled).toBe(true);
|
|
327
|
-
|
|
328
|
-
// Delete the cell
|
|
329
|
-
actions.deleteCell({ cellId: newCellId });
|
|
330
|
-
expect(state.cellIds.inOrderIds).not.toContain(newCellId);
|
|
331
|
-
|
|
332
|
-
// Undo delete
|
|
333
|
-
actions.undoDeleteCell();
|
|
334
|
-
const restoredCellId =
|
|
335
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
336
|
-
|
|
337
|
-
// Config should be preserved
|
|
338
|
-
expect(state.cellData[restoredCellId].config.hide_code).toBe(true);
|
|
339
|
-
expect(state.cellData[restoredCellId].config.disabled).toBe(true);
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it("can update a cell", () => {
|
|
343
|
-
actions.updateCellCode({
|
|
344
|
-
cellId: firstCellId,
|
|
345
|
-
code: "import numpy as np",
|
|
346
|
-
formattingChange: false,
|
|
347
|
-
});
|
|
348
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
349
|
-
"
|
|
350
|
-
[0] 'import numpy as np'
|
|
351
|
-
"
|
|
352
|
-
`);
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
it("can move a cell", () => {
|
|
356
|
-
actions.createNewCell({
|
|
357
|
-
cellId: firstCellId,
|
|
358
|
-
before: false,
|
|
359
|
-
});
|
|
360
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
361
|
-
"
|
|
362
|
-
[0] ''
|
|
363
|
-
|
|
364
|
-
[1] ''
|
|
365
|
-
"
|
|
366
|
-
`);
|
|
367
|
-
|
|
368
|
-
// move first cell to the end
|
|
369
|
-
actions.moveCell({
|
|
370
|
-
cellId: firstCellId,
|
|
371
|
-
before: false,
|
|
372
|
-
});
|
|
373
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
374
|
-
"
|
|
375
|
-
[1] ''
|
|
376
|
-
|
|
377
|
-
[0] ''
|
|
378
|
-
"
|
|
379
|
-
`);
|
|
380
|
-
|
|
381
|
-
// move it back
|
|
382
|
-
actions.moveCell({
|
|
383
|
-
cellId: firstCellId,
|
|
384
|
-
before: true,
|
|
385
|
-
});
|
|
386
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
387
|
-
"
|
|
388
|
-
[0] ''
|
|
389
|
-
|
|
390
|
-
[1] ''
|
|
391
|
-
"
|
|
392
|
-
`);
|
|
393
|
-
|
|
394
|
-
// Add a column breakpoint to test left/right movement
|
|
395
|
-
actions.addColumnBreakpoint({ cellId: cellId("1") });
|
|
396
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
397
|
-
"
|
|
398
|
-
> col 0
|
|
399
|
-
[0] ''
|
|
400
|
-
|
|
401
|
-
> col 1
|
|
402
|
-
[1] ''
|
|
403
|
-
"
|
|
404
|
-
`);
|
|
405
|
-
|
|
406
|
-
// Move cell right
|
|
407
|
-
actions.moveCell({
|
|
408
|
-
cellId: firstCellId,
|
|
409
|
-
direction: "right",
|
|
410
|
-
});
|
|
411
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
412
|
-
"
|
|
413
|
-
> col 0
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
> col 1
|
|
417
|
-
[0] ''
|
|
418
|
-
|
|
419
|
-
[1] ''
|
|
420
|
-
"
|
|
421
|
-
`);
|
|
422
|
-
|
|
423
|
-
// Move cell left
|
|
424
|
-
actions.moveCell({
|
|
425
|
-
cellId: firstCellId,
|
|
426
|
-
direction: "left",
|
|
427
|
-
});
|
|
428
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
429
|
-
"
|
|
430
|
-
> col 0
|
|
431
|
-
[0] ''
|
|
432
|
-
|
|
433
|
-
> col 1
|
|
434
|
-
[1] ''
|
|
435
|
-
"
|
|
436
|
-
`);
|
|
437
|
-
|
|
438
|
-
// Try to move cell left when it's already in leftmost column (should noop)
|
|
439
|
-
actions.moveCell({
|
|
440
|
-
cellId: firstCellId,
|
|
441
|
-
direction: "left",
|
|
442
|
-
});
|
|
443
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
444
|
-
"
|
|
445
|
-
> col 0
|
|
446
|
-
[0] ''
|
|
447
|
-
|
|
448
|
-
> col 1
|
|
449
|
-
[1] ''
|
|
450
|
-
"
|
|
451
|
-
`);
|
|
452
|
-
|
|
453
|
-
// Try to move cell right when it's already in rightmost column (should noop)
|
|
454
|
-
actions.moveCell({
|
|
455
|
-
cellId: cellId("1"),
|
|
456
|
-
direction: "right",
|
|
457
|
-
});
|
|
458
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
459
|
-
"
|
|
460
|
-
> col 0
|
|
461
|
-
[0] ''
|
|
462
|
-
|
|
463
|
-
> col 1
|
|
464
|
-
[1] ''
|
|
465
|
-
"
|
|
466
|
-
`);
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
it("can drag and drop a cell", () => {
|
|
470
|
-
actions.createNewCell({
|
|
471
|
-
cellId: firstCellId,
|
|
472
|
-
before: false,
|
|
473
|
-
});
|
|
474
|
-
actions.createNewCell({
|
|
475
|
-
cellId: cellId("1"),
|
|
476
|
-
before: false,
|
|
477
|
-
});
|
|
478
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
479
|
-
"
|
|
480
|
-
[0] ''
|
|
481
|
-
|
|
482
|
-
[1] ''
|
|
483
|
-
|
|
484
|
-
[2] ''
|
|
485
|
-
"
|
|
486
|
-
`);
|
|
487
|
-
|
|
488
|
-
// drag first cell to the end
|
|
489
|
-
actions.dropCellOverCell({
|
|
490
|
-
cellId: firstCellId,
|
|
491
|
-
overCellId: cellId("2"),
|
|
492
|
-
});
|
|
493
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
494
|
-
"
|
|
495
|
-
[1] ''
|
|
496
|
-
|
|
497
|
-
[2] ''
|
|
498
|
-
|
|
499
|
-
[0] ''
|
|
500
|
-
"
|
|
501
|
-
`);
|
|
502
|
-
|
|
503
|
-
// drag it back to the middle
|
|
504
|
-
actions.dropCellOverCell({
|
|
505
|
-
cellId: firstCellId,
|
|
506
|
-
overCellId: cellId("2"),
|
|
507
|
-
});
|
|
508
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
509
|
-
"
|
|
510
|
-
[1] ''
|
|
511
|
-
|
|
512
|
-
[0] ''
|
|
513
|
-
|
|
514
|
-
[2] ''
|
|
515
|
-
"
|
|
516
|
-
`);
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
it("can move a cell to an exact index within a column", () => {
|
|
520
|
-
actions.createNewCell({
|
|
521
|
-
cellId: firstCellId,
|
|
522
|
-
before: false,
|
|
523
|
-
});
|
|
524
|
-
actions.createNewCell({
|
|
525
|
-
cellId: cellId("1"),
|
|
526
|
-
before: false,
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
const columnId = state.cellIds.atOrThrow(0).id;
|
|
530
|
-
actions.moveCellToIndex({
|
|
531
|
-
cellId: firstCellId,
|
|
532
|
-
columnId,
|
|
533
|
-
index: 3,
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
537
|
-
"
|
|
538
|
-
[1] ''
|
|
539
|
-
|
|
540
|
-
[2] ''
|
|
541
|
-
|
|
542
|
-
[0] ''
|
|
543
|
-
"
|
|
544
|
-
`);
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
it("can move a cell to an exact index across columns", () => {
|
|
548
|
-
actions.createNewCell({
|
|
549
|
-
cellId: firstCellId,
|
|
550
|
-
before: false,
|
|
551
|
-
});
|
|
552
|
-
actions.createNewCell({
|
|
553
|
-
cellId: cellId("1"),
|
|
554
|
-
before: false,
|
|
555
|
-
});
|
|
556
|
-
actions.addColumnBreakpoint({ cellId: cellId("1") });
|
|
557
|
-
|
|
558
|
-
const secondColumnId = state.cellIds.atOrThrow(1).id;
|
|
559
|
-
actions.moveCellToIndex({
|
|
560
|
-
cellId: firstCellId,
|
|
561
|
-
columnId: secondColumnId,
|
|
562
|
-
index: 1,
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
566
|
-
"
|
|
567
|
-
> col 0
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
> col 1
|
|
571
|
-
[1] ''
|
|
572
|
-
|
|
573
|
-
[0] ''
|
|
574
|
-
|
|
575
|
-
[2] ''
|
|
576
|
-
"
|
|
577
|
-
`);
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
it("moveCellToIndex is a no-op when moving to the same position", () => {
|
|
581
|
-
actions.createNewCell({
|
|
582
|
-
cellId: firstCellId,
|
|
583
|
-
before: false,
|
|
584
|
-
});
|
|
585
|
-
actions.createNewCell({
|
|
586
|
-
cellId: cellId("1"),
|
|
587
|
-
before: false,
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
const columnId = state.cellIds.atOrThrow(0).id;
|
|
591
|
-
const before = formatCells(state);
|
|
592
|
-
|
|
593
|
-
actions.moveCellToIndex({
|
|
594
|
-
cellId: firstCellId,
|
|
595
|
-
columnId,
|
|
596
|
-
index: 0,
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
expect(formatCells(state)).toBe(before);
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
it("moveCellToIndex is a no-op for an invalid columnId", () => {
|
|
603
|
-
actions.createNewCell({
|
|
604
|
-
cellId: firstCellId,
|
|
605
|
-
before: false,
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
const before = formatCells(state);
|
|
609
|
-
|
|
610
|
-
actions.moveCellToIndex({
|
|
611
|
-
cellId: firstCellId,
|
|
612
|
-
columnId: "nonexistent-column" as CellColumnId,
|
|
613
|
-
index: 0,
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
expect(formatCells(state)).toBe(before);
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
it("can move multiple cells relative to target", () => {
|
|
620
|
-
actions.createNewCell({
|
|
621
|
-
cellId: firstCellId,
|
|
622
|
-
before: false,
|
|
623
|
-
});
|
|
624
|
-
actions.createNewCell({
|
|
625
|
-
cellId: cellId("1"),
|
|
626
|
-
before: false,
|
|
627
|
-
});
|
|
628
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
629
|
-
"
|
|
630
|
-
[0] ''
|
|
631
|
-
|
|
632
|
-
[1] ''
|
|
633
|
-
|
|
634
|
-
[2] ''
|
|
635
|
-
"
|
|
636
|
-
`);
|
|
637
|
-
|
|
638
|
-
// Move first two cells after the third
|
|
639
|
-
actions.moveCellsRelativeTo({
|
|
640
|
-
cellIds: [firstCellId, cellId("1")],
|
|
641
|
-
targetCellId: cellId("2"),
|
|
642
|
-
position: "after",
|
|
643
|
-
});
|
|
644
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
645
|
-
"
|
|
646
|
-
[2] ''
|
|
647
|
-
|
|
648
|
-
[0] ''
|
|
649
|
-
|
|
650
|
-
[1] ''
|
|
651
|
-
"
|
|
652
|
-
`);
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
it("can undo cut-paste (move with previousPlacements)", () => {
|
|
656
|
-
actions.createNewCell({
|
|
657
|
-
cellId: firstCellId,
|
|
658
|
-
before: false,
|
|
659
|
-
});
|
|
660
|
-
actions.createNewCell({
|
|
661
|
-
cellId: cellId("1"),
|
|
662
|
-
before: false,
|
|
663
|
-
});
|
|
664
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
665
|
-
"
|
|
666
|
-
[0] ''
|
|
667
|
-
|
|
668
|
-
[1] ''
|
|
669
|
-
|
|
670
|
-
[2] ''
|
|
671
|
-
"
|
|
672
|
-
`);
|
|
673
|
-
|
|
674
|
-
const col = state.cellIds.findWithId(firstCellId);
|
|
675
|
-
const previousPlacements = [
|
|
676
|
-
{
|
|
677
|
-
columnId: col.id,
|
|
678
|
-
index: col.indexOfOrThrow(
|
|
679
|
-
firstCellId,
|
|
680
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
681
|
-
},
|
|
682
|
-
{
|
|
683
|
-
columnId: col.id,
|
|
684
|
-
index: col.indexOfOrThrow(
|
|
685
|
-
cellId("1"),
|
|
686
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
687
|
-
},
|
|
688
|
-
];
|
|
689
|
-
|
|
690
|
-
actions.moveCellsRelativeTo({
|
|
691
|
-
cellIds: [firstCellId, cellId("1")],
|
|
692
|
-
targetCellId: cellId("2"),
|
|
693
|
-
position: "after",
|
|
694
|
-
previousPlacements,
|
|
695
|
-
});
|
|
696
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
697
|
-
"
|
|
698
|
-
[2] ''
|
|
699
|
-
|
|
700
|
-
[0] ''
|
|
701
|
-
|
|
702
|
-
[1] ''
|
|
703
|
-
"
|
|
704
|
-
`);
|
|
705
|
-
|
|
706
|
-
actions.undoDeleteCell();
|
|
707
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
708
|
-
"
|
|
709
|
-
[0] ''
|
|
710
|
-
|
|
711
|
-
[1] ''
|
|
712
|
-
|
|
713
|
-
[2] ''
|
|
714
|
-
"
|
|
715
|
-
`);
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
it("undo order: cut-paste then delete — first undo restores delete, second undo undoes move", () => {
|
|
719
|
-
actions.createNewCell({
|
|
720
|
-
cellId: firstCellId,
|
|
721
|
-
before: false,
|
|
722
|
-
});
|
|
723
|
-
actions.createNewCell({
|
|
724
|
-
cellId: cellId("1"),
|
|
725
|
-
before: false,
|
|
726
|
-
});
|
|
727
|
-
|
|
728
|
-
const col = state.cellIds.findWithId(firstCellId);
|
|
729
|
-
const previousPlacements = [
|
|
730
|
-
{
|
|
731
|
-
columnId: col.id,
|
|
732
|
-
index: col.indexOfOrThrow(
|
|
733
|
-
firstCellId,
|
|
734
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
735
|
-
},
|
|
736
|
-
{
|
|
737
|
-
columnId: col.id,
|
|
738
|
-
index: col.indexOfOrThrow(
|
|
739
|
-
cellId("1"),
|
|
740
|
-
) as import("@/utils/id-tree").CellIndex,
|
|
741
|
-
},
|
|
742
|
-
];
|
|
743
|
-
|
|
744
|
-
actions.moveCellsRelativeTo({
|
|
745
|
-
cellIds: [firstCellId, cellId("1")],
|
|
746
|
-
targetCellId: cellId("2"),
|
|
747
|
-
position: "after",
|
|
748
|
-
previousPlacements,
|
|
749
|
-
});
|
|
750
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
751
|
-
"
|
|
752
|
-
[2] ''
|
|
753
|
-
|
|
754
|
-
[0] ''
|
|
755
|
-
|
|
756
|
-
[1] ''
|
|
757
|
-
"
|
|
758
|
-
`);
|
|
759
|
-
|
|
760
|
-
actions.deleteCell({ cellId: cellId("2") });
|
|
761
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
762
|
-
"
|
|
763
|
-
[0] ''
|
|
764
|
-
|
|
765
|
-
[1] ''
|
|
766
|
-
"
|
|
767
|
-
`);
|
|
768
|
-
|
|
769
|
-
actions.undoDeleteCell();
|
|
770
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
771
|
-
"
|
|
772
|
-
[3] ''
|
|
773
|
-
|
|
774
|
-
[0] ''
|
|
775
|
-
|
|
776
|
-
[1] ''
|
|
777
|
-
"
|
|
778
|
-
`);
|
|
779
|
-
|
|
780
|
-
actions.undoDeleteCell();
|
|
781
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
782
|
-
"
|
|
783
|
-
[0] ''
|
|
784
|
-
|
|
785
|
-
[1] ''
|
|
786
|
-
|
|
787
|
-
[3] ''
|
|
788
|
-
"
|
|
789
|
-
`);
|
|
790
|
-
});
|
|
791
|
-
|
|
792
|
-
it("keeps error evidence after an edit and a new queued run", () => {
|
|
793
|
-
const code = "raise ValueError('old failure')";
|
|
794
|
-
const output: OutputMessage = {
|
|
795
|
-
channel: "marimo-error",
|
|
796
|
-
mimetype: "application/vnd.marimo+error",
|
|
797
|
-
data: [
|
|
798
|
-
{
|
|
799
|
-
type: "exception",
|
|
800
|
-
msg: "old failure",
|
|
801
|
-
exception_type: "ValueError",
|
|
802
|
-
raising_cell: null,
|
|
803
|
-
traceback: "<pre>ValueError: old failure</pre>",
|
|
804
|
-
},
|
|
805
|
-
],
|
|
806
|
-
code,
|
|
807
|
-
timestamp: 1,
|
|
808
|
-
};
|
|
809
|
-
actions.handleCellMessage({
|
|
810
|
-
cell_id: firstCellId,
|
|
811
|
-
output,
|
|
812
|
-
console: {
|
|
813
|
-
channel: "stderr",
|
|
814
|
-
mimetype: "application/vnd.marimo+traceback",
|
|
815
|
-
data: "<pre>ValueError: old failure</pre>",
|
|
816
|
-
code,
|
|
817
|
-
timestamp: 1,
|
|
818
|
-
},
|
|
819
|
-
status: "idle",
|
|
820
|
-
stale_inputs: null,
|
|
821
|
-
timestamp: 1,
|
|
822
|
-
});
|
|
823
|
-
actions.updateCellCode({
|
|
824
|
-
cellId: firstCellId,
|
|
825
|
-
code: "print('new code')",
|
|
826
|
-
formattingChange: false,
|
|
827
|
-
});
|
|
828
|
-
actions.prepareForRun({ cellId: firstCellId });
|
|
829
|
-
actions.handleCellMessage({
|
|
830
|
-
cell_id: firstCellId,
|
|
831
|
-
output: null,
|
|
832
|
-
console: null,
|
|
833
|
-
status: "queued",
|
|
834
|
-
stale_inputs: null,
|
|
835
|
-
timestamp: 2,
|
|
836
|
-
});
|
|
837
|
-
const runtime = state.cellRuntime[firstCellId];
|
|
838
|
-
expect(state.cellData[firstCellId].lastCodeRun).toBe("print('new code')");
|
|
839
|
-
expect(runtime.output).toEqual(output);
|
|
840
|
-
expect(runtime.consoleOutputs[0].code).toBe(code);
|
|
841
|
-
expect(runtime.consoleOutputs[0].data).toContain("old failure");
|
|
842
|
-
});
|
|
843
|
-
|
|
844
|
-
it("can run cell and receive cell messages", () => {
|
|
845
|
-
// HAPPY PATH
|
|
846
|
-
/////////////////
|
|
847
|
-
// Initial state
|
|
848
|
-
let cell = cells[0];
|
|
849
|
-
expect(cell.status).toBe("idle");
|
|
850
|
-
expect(cell.lastCodeRun).toBe(null);
|
|
851
|
-
expect(cell.edited).toBe(false);
|
|
852
|
-
expect(cell).toMatchSnapshot("initial state");
|
|
853
|
-
|
|
854
|
-
// Update code
|
|
855
|
-
actions.updateCellCode({
|
|
856
|
-
cellId: firstCellId,
|
|
857
|
-
code: "import marimo as mo",
|
|
858
|
-
formattingChange: false,
|
|
859
|
-
});
|
|
860
|
-
cell = cells[0];
|
|
861
|
-
expect(cell.status).toBe("idle");
|
|
862
|
-
expect(cell.lastCodeRun).toBe(null);
|
|
863
|
-
expect(cell.edited).toBe(true);
|
|
864
|
-
expect(cell).toMatchSnapshot("code edited");
|
|
865
|
-
|
|
866
|
-
// Prepare for run
|
|
867
|
-
actions.prepareForRun({
|
|
868
|
-
cellId: firstCellId,
|
|
869
|
-
});
|
|
870
|
-
cell = cells[0];
|
|
871
|
-
expect(cell.status).toBe("queued");
|
|
872
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
873
|
-
expect(cell.edited).toBe(false);
|
|
874
|
-
expect(cell).toMatchSnapshot("prepared for run");
|
|
875
|
-
|
|
876
|
-
// Receive queued messages
|
|
877
|
-
actions.handleCellMessage({
|
|
878
|
-
cell_id: firstCellId,
|
|
879
|
-
output: undefined,
|
|
880
|
-
console: null,
|
|
881
|
-
status: "queued",
|
|
882
|
-
stale_inputs: null,
|
|
883
|
-
timestamp: new Date(10).getTime() as Seconds,
|
|
884
|
-
});
|
|
885
|
-
cell = cells[0];
|
|
886
|
-
expect(cell.status).toBe("queued");
|
|
887
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
888
|
-
expect(cell.edited).toBe(false);
|
|
889
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
890
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
891
|
-
expect(cell.lastRunStartTimestamp).toBe(null);
|
|
892
|
-
expect(cell).toMatchSnapshot("queued message received");
|
|
893
|
-
|
|
894
|
-
// Receive running messages
|
|
895
|
-
actions.handleCellMessage({
|
|
896
|
-
cell_id: firstCellId,
|
|
897
|
-
output: undefined,
|
|
898
|
-
console: null,
|
|
899
|
-
status: "running",
|
|
900
|
-
stale_inputs: null,
|
|
901
|
-
timestamp: new Date(20).getTime() as Seconds,
|
|
902
|
-
});
|
|
903
|
-
cell = cells[0];
|
|
904
|
-
expect(cell.status).toBe("running");
|
|
905
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
906
|
-
expect(cell.edited).toBe(false);
|
|
907
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
908
|
-
expect(cell.runStartTimestamp).toBe(20);
|
|
909
|
-
expect(cell.lastRunStartTimestamp).toBe(20);
|
|
910
|
-
expect(cell).toMatchSnapshot("running message received");
|
|
911
|
-
|
|
912
|
-
// Console messages shouldn't transition status
|
|
913
|
-
actions.handleCellMessage({
|
|
914
|
-
cell_id: firstCellId,
|
|
915
|
-
output: undefined,
|
|
916
|
-
console: {
|
|
917
|
-
channel: "stdout",
|
|
918
|
-
mimetype: "text/plain",
|
|
919
|
-
data: "hello!",
|
|
920
|
-
timestamp: 0,
|
|
921
|
-
},
|
|
922
|
-
status: undefined,
|
|
923
|
-
stale_inputs: null,
|
|
924
|
-
timestamp: new Date(22).getTime() as Seconds,
|
|
925
|
-
});
|
|
926
|
-
cell = cells[0];
|
|
927
|
-
expect(cell.status).toBe("running");
|
|
928
|
-
expect(cell.edited).toBe(false);
|
|
929
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
930
|
-
expect(cell.runStartTimestamp).toBe(20);
|
|
931
|
-
expect(cell.lastRunStartTimestamp).toBe(20);
|
|
932
|
-
expect(cell).toMatchSnapshot("console message received");
|
|
933
|
-
|
|
934
|
-
// Receive output messages
|
|
935
|
-
actions.handleCellMessage({
|
|
936
|
-
cell_id: firstCellId,
|
|
937
|
-
output: {
|
|
938
|
-
channel: "output",
|
|
939
|
-
mimetype: "text/plain",
|
|
940
|
-
data: "ok",
|
|
941
|
-
timestamp: 0,
|
|
942
|
-
},
|
|
943
|
-
console: {
|
|
944
|
-
channel: "stdout",
|
|
945
|
-
mimetype: "text/plain",
|
|
946
|
-
data: "hello!",
|
|
947
|
-
timestamp: 0,
|
|
948
|
-
},
|
|
949
|
-
status: "idle",
|
|
950
|
-
stale_inputs: null,
|
|
951
|
-
timestamp: new Date(33).getTime() as Seconds,
|
|
952
|
-
});
|
|
953
|
-
cell = cells[0];
|
|
954
|
-
expect(cell.status).toBe("idle");
|
|
955
|
-
expect(cell.edited).toBe(false);
|
|
956
|
-
expect(cell.runElapsedTimeMs).toBe(13_000);
|
|
957
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
958
|
-
expect(cell.lastRunStartTimestamp).toBe(20);
|
|
959
|
-
expect(cell).toMatchSnapshot("output received");
|
|
960
|
-
|
|
961
|
-
// EDITING BACK AND FORTH
|
|
962
|
-
/////////////////
|
|
963
|
-
// Update code again
|
|
964
|
-
actions.updateCellCode({
|
|
965
|
-
cellId: firstCellId,
|
|
966
|
-
code: "import marimo as mo\nimport numpy",
|
|
967
|
-
formattingChange: false,
|
|
968
|
-
});
|
|
969
|
-
cell = cells[0];
|
|
970
|
-
expect(cell.status).toBe("idle");
|
|
971
|
-
expect(cell.edited).toBe(true);
|
|
972
|
-
expect(cell).toMatchSnapshot("code edited again");
|
|
973
|
-
|
|
974
|
-
// Update code should be unedited
|
|
975
|
-
actions.updateCellCode({
|
|
976
|
-
cellId: firstCellId,
|
|
977
|
-
code: "import marimo as mo",
|
|
978
|
-
formattingChange: false,
|
|
979
|
-
});
|
|
980
|
-
cell = cells[0];
|
|
981
|
-
expect(cell.edited).toBe(false);
|
|
982
|
-
expect(cell).toMatchSnapshot("code reverted");
|
|
983
|
-
|
|
984
|
-
// Update code should be edited again
|
|
985
|
-
actions.updateCellCode({
|
|
986
|
-
cellId: firstCellId,
|
|
987
|
-
code: "import marimo as mo\nimport numpy",
|
|
988
|
-
formattingChange: false,
|
|
989
|
-
});
|
|
990
|
-
cell = cells[0];
|
|
991
|
-
expect(cell.status).toBe("idle");
|
|
992
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
993
|
-
expect(cell.edited).toBe(true);
|
|
994
|
-
expect(cell).toMatchSnapshot("code changed after revert");
|
|
995
|
-
|
|
996
|
-
// ERROR RESPONSE
|
|
997
|
-
/////////////////
|
|
998
|
-
// Prepare for run
|
|
999
|
-
actions.prepareForRun({
|
|
1000
|
-
cellId: firstCellId,
|
|
1001
|
-
});
|
|
1002
|
-
cell = cells[0];
|
|
1003
|
-
expect(cell.output).not.toBe(null); // keep old output
|
|
1004
|
-
// Queue
|
|
1005
|
-
actions.handleCellMessage({
|
|
1006
|
-
cell_id: firstCellId,
|
|
1007
|
-
output: undefined,
|
|
1008
|
-
console: null,
|
|
1009
|
-
status: "queued",
|
|
1010
|
-
stale_inputs: null,
|
|
1011
|
-
timestamp: new Date(40).getTime() as Seconds,
|
|
1012
|
-
});
|
|
1013
|
-
cell = cells[0];
|
|
1014
|
-
expect(cell.output).not.toBe(null); // keep old output
|
|
1015
|
-
// Running
|
|
1016
|
-
actions.handleCellMessage({
|
|
1017
|
-
cell_id: firstCellId,
|
|
1018
|
-
output: undefined,
|
|
1019
|
-
console: null,
|
|
1020
|
-
status: "running",
|
|
1021
|
-
stale_inputs: null,
|
|
1022
|
-
timestamp: new Date(50).getTime() as Seconds,
|
|
1023
|
-
});
|
|
1024
|
-
cell = cells[0];
|
|
1025
|
-
expect(cell.output).not.toBe(null); // keep old output
|
|
1026
|
-
// Receive error
|
|
1027
|
-
actions.handleCellMessage({
|
|
1028
|
-
cell_id: firstCellId,
|
|
1029
|
-
output: {
|
|
1030
|
-
channel: "marimo-error",
|
|
1031
|
-
mimetype: "application/vnd.marimo+error",
|
|
1032
|
-
data: [
|
|
1033
|
-
{ type: "exception", exception_type: "ValueError", msg: "Oh no!" },
|
|
1034
|
-
],
|
|
1035
|
-
timestamp: 0,
|
|
1036
|
-
},
|
|
1037
|
-
console: null,
|
|
1038
|
-
status: "idle",
|
|
1039
|
-
stale_inputs: null,
|
|
1040
|
-
timestamp: new Date(61).getTime() as Seconds,
|
|
1041
|
-
});
|
|
1042
|
-
cell = cells[0];
|
|
1043
|
-
expect(cell.output).not.toBe(null); // keep old output
|
|
1044
|
-
expect(cell.status).toBe("idle");
|
|
1045
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo\nimport numpy");
|
|
1046
|
-
expect(cell.edited).toBe(false);
|
|
1047
|
-
expect(cell.runElapsedTimeMs).toBe(11_000);
|
|
1048
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
1049
|
-
expect(cell).toMatchSnapshot("error response received");
|
|
1050
|
-
|
|
1051
|
-
// INTERRUPT RESPONSE
|
|
1052
|
-
/////////////////
|
|
1053
|
-
// Prepare for run
|
|
1054
|
-
actions.prepareForRun({
|
|
423
|
+
// INTERRUPT RESPONSE
|
|
424
|
+
/////////////////
|
|
425
|
+
// Prepare for run
|
|
426
|
+
actions.prepareForRun({
|
|
1055
427
|
cellId: firstCellId,
|
|
1056
428
|
});
|
|
1057
429
|
cell = cells[0];
|
|
@@ -1062,7 +434,6 @@ describe("cell reducer", () => {
|
|
|
1062
434
|
output: undefined,
|
|
1063
435
|
console: null,
|
|
1064
436
|
status: "queued",
|
|
1065
|
-
stale_inputs: null,
|
|
1066
437
|
timestamp: new Date(40).getTime() as Seconds,
|
|
1067
438
|
});
|
|
1068
439
|
cell = cells[0];
|
|
@@ -1073,7 +444,6 @@ describe("cell reducer", () => {
|
|
|
1073
444
|
output: undefined,
|
|
1074
445
|
console: null,
|
|
1075
446
|
status: "running",
|
|
1076
|
-
stale_inputs: null,
|
|
1077
447
|
timestamp: new Date(50).getTime() as Seconds,
|
|
1078
448
|
});
|
|
1079
449
|
cell = cells[0];
|
|
@@ -1089,100 +459,23 @@ describe("cell reducer", () => {
|
|
|
1089
459
|
},
|
|
1090
460
|
console: null,
|
|
1091
461
|
status: "idle",
|
|
1092
|
-
stale_inputs: null,
|
|
1093
462
|
timestamp: new Date(61).getTime() as Seconds,
|
|
1094
463
|
});
|
|
1095
464
|
cell = cells[0];
|
|
1096
|
-
expect(cell.status).toBe("idle");
|
|
1097
|
-
expect(cell.lastCodeRun).toBe(cell.code);
|
|
1098
|
-
expect(cell.edited).toBe(false);
|
|
1099
|
-
expect(cell.runElapsedTimeMs).toBe(11_000);
|
|
1100
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
1101
465
|
expect(cell).toMatchSnapshot("interruption response received");
|
|
1102
466
|
});
|
|
1103
467
|
|
|
1104
|
-
it("errors reset status to idle", () => {
|
|
1105
|
-
// Initial state
|
|
1106
|
-
let cell = cells[0];
|
|
1107
|
-
expect(cell.status).toBe("idle");
|
|
1108
|
-
expect(cell.lastCodeRun).toBe(null);
|
|
1109
|
-
expect(cell.edited).toBe(false);
|
|
1110
|
-
expect(cell).toMatchSnapshot("initial state");
|
|
1111
|
-
|
|
1112
|
-
// Update code
|
|
1113
|
-
actions.updateCellCode({
|
|
1114
|
-
cellId: firstCellId,
|
|
1115
|
-
code: "import marimo as mo",
|
|
1116
|
-
formattingChange: false,
|
|
1117
|
-
});
|
|
1118
|
-
cell = cells[0];
|
|
1119
|
-
expect(cell.status).toBe("idle");
|
|
1120
|
-
expect(cell.lastCodeRun).toBe(null);
|
|
1121
|
-
expect(cell.edited).toBe(true);
|
|
1122
|
-
expect(cell).toMatchSnapshot("code edited");
|
|
1123
|
-
|
|
1124
|
-
// Prepare for run
|
|
1125
|
-
actions.prepareForRun({
|
|
1126
|
-
cellId: firstCellId,
|
|
1127
|
-
});
|
|
1128
|
-
cell = cells[0];
|
|
1129
|
-
expect(cell.status).toBe("queued");
|
|
1130
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
1131
|
-
expect(cell.edited).toBe(false);
|
|
1132
|
-
expect(cell).toMatchSnapshot("prepared for run");
|
|
1133
|
-
|
|
1134
|
-
// ERROR RESPONSE
|
|
1135
|
-
//
|
|
1136
|
-
// should reset status to idle
|
|
1137
|
-
/////////////////
|
|
1138
|
-
// Prepare for run
|
|
1139
|
-
actions.prepareForRun({
|
|
1140
|
-
cellId: firstCellId,
|
|
1141
|
-
});
|
|
1142
|
-
cell = cells[0];
|
|
1143
|
-
// Receive error
|
|
1144
|
-
actions.handleCellMessage({
|
|
1145
|
-
cell_id: firstCellId,
|
|
1146
|
-
output: {
|
|
1147
|
-
channel: "marimo-error",
|
|
1148
|
-
mimetype: "application/vnd.marimo+error",
|
|
1149
|
-
data: [
|
|
1150
|
-
{ type: "exception", exception_type: "SyntaxError", msg: "Oh no!" },
|
|
1151
|
-
],
|
|
1152
|
-
timestamp: 0,
|
|
1153
|
-
},
|
|
1154
|
-
console: null,
|
|
1155
|
-
stale_inputs: null,
|
|
1156
|
-
timestamp: new Date(61).getTime() as Seconds,
|
|
1157
|
-
});
|
|
1158
|
-
cell = cells[0];
|
|
1159
|
-
expect(cell.status).toBe("idle");
|
|
1160
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
1161
|
-
expect(cell.edited).toBe(false);
|
|
1162
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
1163
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
1164
|
-
expect(cell).toMatchSnapshot("error response received");
|
|
1165
|
-
});
|
|
1166
|
-
|
|
1167
468
|
it("can run a stale cell", () => {
|
|
1168
469
|
// Update code of first cell
|
|
1169
|
-
|
|
1170
|
-
cellId: firstCellId,
|
|
1171
|
-
code: "import marimo as mo",
|
|
1172
|
-
formattingChange: false,
|
|
1173
|
-
});
|
|
470
|
+
editCode(firstCellId, "import marimo as mo");
|
|
1174
471
|
// Add cell
|
|
1175
|
-
|
|
472
|
+
seedCell({
|
|
1176
473
|
cellId: firstCellId,
|
|
1177
474
|
before: false,
|
|
1178
475
|
});
|
|
1179
476
|
const secondCell = cells[1].id;
|
|
1180
|
-
// Update code
|
|
1181
|
-
|
|
1182
|
-
code: "mo.slider()",
|
|
1183
|
-
cellId: secondCell,
|
|
1184
|
-
formattingChange: false,
|
|
1185
|
-
});
|
|
477
|
+
// Update code
|
|
478
|
+
editCode(secondCell, "mo.slider()");
|
|
1186
479
|
|
|
1187
480
|
// Prepare for run
|
|
1188
481
|
actions.prepareForRun({
|
|
@@ -1195,15 +488,9 @@ describe("cell reducer", () => {
|
|
|
1195
488
|
output: undefined,
|
|
1196
489
|
console: null,
|
|
1197
490
|
status: "queued",
|
|
1198
|
-
stale_inputs: null,
|
|
1199
491
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1200
492
|
});
|
|
1201
493
|
let cell = cells[1];
|
|
1202
|
-
expect(cell.status).toBe("queued");
|
|
1203
|
-
expect(cell.lastCodeRun).toBe("mo.slider()");
|
|
1204
|
-
expect(cell.edited).toBe(false);
|
|
1205
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
1206
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
1207
494
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1208
495
|
|
|
1209
496
|
// Receive stale message
|
|
@@ -1212,105 +499,15 @@ describe("cell reducer", () => {
|
|
|
1212
499
|
output: undefined,
|
|
1213
500
|
console: null,
|
|
1214
501
|
status: undefined,
|
|
1215
|
-
stale_inputs: true,
|
|
1216
502
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1217
503
|
});
|
|
1218
504
|
cell = cells[1];
|
|
1219
|
-
expect(cell.status).toBe("queued");
|
|
1220
|
-
expect(cell.lastCodeRun).toBe("mo.slider()");
|
|
1221
|
-
expect(cell.edited).toBe(false);
|
|
1222
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
1223
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
1224
505
|
expect(cell).toMatchSnapshot("stale inputs received");
|
|
1225
506
|
});
|
|
1226
507
|
|
|
1227
|
-
it("can format code and update cell", () => {
|
|
1228
|
-
const firstCellId = cells[0].id;
|
|
1229
|
-
actions.updateCellCode({
|
|
1230
|
-
cellId: firstCellId,
|
|
1231
|
-
code: "import marimo as mo",
|
|
1232
|
-
formattingChange: false,
|
|
1233
|
-
});
|
|
1234
|
-
let cell = cells[0];
|
|
1235
|
-
expect(cell.status).toBe("idle");
|
|
1236
|
-
expect(cell.lastCodeRun).toBe(null);
|
|
1237
|
-
expect(cell.edited).toBe(true);
|
|
1238
|
-
|
|
1239
|
-
// Run
|
|
1240
|
-
actions.prepareForRun({
|
|
1241
|
-
cellId: firstCellId,
|
|
1242
|
-
});
|
|
1243
|
-
actions.handleCellMessage({
|
|
1244
|
-
cell_id: firstCellId,
|
|
1245
|
-
output: {
|
|
1246
|
-
channel: "output",
|
|
1247
|
-
mimetype: "text/plain",
|
|
1248
|
-
data: "ok",
|
|
1249
|
-
timestamp: 0,
|
|
1250
|
-
},
|
|
1251
|
-
console: {
|
|
1252
|
-
channel: "stdout",
|
|
1253
|
-
mimetype: "text/plain",
|
|
1254
|
-
data: "hello!",
|
|
1255
|
-
timestamp: 0,
|
|
1256
|
-
},
|
|
1257
|
-
status: "idle",
|
|
1258
|
-
stale_inputs: null,
|
|
1259
|
-
timestamp: new Date(33).getTime() as Seconds,
|
|
1260
|
-
});
|
|
1261
|
-
|
|
1262
|
-
// Check steady state
|
|
1263
|
-
cell = cells[0];
|
|
1264
|
-
expect(cell.status).toBe("idle");
|
|
1265
|
-
expect(cell.edited).toBe(false);
|
|
1266
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
1267
|
-
|
|
1268
|
-
// Format code
|
|
1269
|
-
actions.updateCellCode({
|
|
1270
|
-
cellId: firstCellId,
|
|
1271
|
-
code: "import marimo as mo",
|
|
1272
|
-
formattingChange: true,
|
|
1273
|
-
});
|
|
1274
|
-
cell = cells[0];
|
|
1275
|
-
expect(cell.status).toBe("idle");
|
|
1276
|
-
expect(cell.lastCodeRun).toBe("import marimo as mo");
|
|
1277
|
-
expect(cell.edited).toBe(false);
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
it("can update a cells config", () => {
|
|
1281
|
-
const firstCellId = cells[0].id;
|
|
1282
|
-
let cell = cells[0];
|
|
1283
|
-
// Starts empty
|
|
1284
|
-
expect(cell.config).toEqual({
|
|
1285
|
-
disabled: false,
|
|
1286
|
-
hide_code: false,
|
|
1287
|
-
column: null,
|
|
1288
|
-
expand_output: false,
|
|
1289
|
-
});
|
|
1290
|
-
|
|
1291
|
-
actions.updateCellConfig({
|
|
1292
|
-
cellId: firstCellId,
|
|
1293
|
-
config: { disabled: true },
|
|
1294
|
-
});
|
|
1295
|
-
cell = cells[0];
|
|
1296
|
-
expect(cell.config.disabled).toBe(true);
|
|
1297
|
-
|
|
1298
|
-
// Revert
|
|
1299
|
-
actions.updateCellConfig({
|
|
1300
|
-
cellId: firstCellId,
|
|
1301
|
-
config: { disabled: false },
|
|
1302
|
-
});
|
|
1303
|
-
cell = cells[0];
|
|
1304
|
-
expect(cell.config.disabled).toBe(false);
|
|
1305
|
-
});
|
|
1306
|
-
|
|
1307
508
|
it("can run a stopped cell", () => {
|
|
1308
509
|
// Update code of first cell
|
|
1309
|
-
|
|
1310
|
-
cellId: firstCellId,
|
|
1311
|
-
code: "mo.md('This has an ancestor that was stopped')",
|
|
1312
|
-
formattingChange: false,
|
|
1313
|
-
});
|
|
510
|
+
editCode(firstCellId, "mo.md('This has an ancestor that was stopped')");
|
|
1314
511
|
|
|
1315
512
|
// Prepare for run
|
|
1316
513
|
actions.prepareForRun({
|
|
@@ -1323,17 +520,9 @@ describe("cell reducer", () => {
|
|
|
1323
520
|
output: undefined,
|
|
1324
521
|
console: null,
|
|
1325
522
|
status: "queued",
|
|
1326
|
-
stale_inputs: null,
|
|
1327
523
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1328
524
|
});
|
|
1329
525
|
let cell = cells[0];
|
|
1330
|
-
expect(cell.status).toBe("queued");
|
|
1331
|
-
expect(cell.lastCodeRun).toBe(
|
|
1332
|
-
"mo.md('This has an ancestor that was stopped')",
|
|
1333
|
-
);
|
|
1334
|
-
expect(cell.edited).toBe(false);
|
|
1335
|
-
expect(cell.runElapsedTimeMs).toBe(null);
|
|
1336
|
-
expect(cell.runStartTimestamp).toBe(null);
|
|
1337
526
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1338
527
|
|
|
1339
528
|
// Receive idle message
|
|
@@ -1342,7 +531,6 @@ describe("cell reducer", () => {
|
|
|
1342
531
|
output: undefined,
|
|
1343
532
|
console: null,
|
|
1344
533
|
status: "idle",
|
|
1345
|
-
stale_inputs: null,
|
|
1346
534
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1347
535
|
});
|
|
1348
536
|
cell = cells[0];
|
|
@@ -1365,16 +553,13 @@ describe("cell reducer", () => {
|
|
|
1365
553
|
},
|
|
1366
554
|
console: null,
|
|
1367
555
|
status: "idle",
|
|
1368
|
-
stale_inputs: null,
|
|
1369
556
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1370
557
|
});
|
|
1371
558
|
cell = cells[0];
|
|
1372
|
-
expect(cell.status).toBe("idle");
|
|
1373
559
|
// oxlint-disable-next-line typescript/no-explicit-any no-unsafe-optional-chaining
|
|
1374
560
|
expect((cell.output?.data as any)[0].msg).toBe(
|
|
1375
561
|
"This cell wasn't run because an ancestor was stopped with `mo.stop`: ",
|
|
1376
562
|
);
|
|
1377
|
-
expect(cell.stopped).toBe(true);
|
|
1378
563
|
expect(cell).toMatchSnapshot("ancestor stopped");
|
|
1379
564
|
|
|
1380
565
|
// Receive queued message
|
|
@@ -1383,12 +568,9 @@ describe("cell reducer", () => {
|
|
|
1383
568
|
output: undefined,
|
|
1384
569
|
console: null,
|
|
1385
570
|
status: "queued",
|
|
1386
|
-
stale_inputs: null,
|
|
1387
571
|
timestamp: new Date(30).getTime() as Seconds,
|
|
1388
572
|
});
|
|
1389
573
|
cell = cells[0];
|
|
1390
|
-
expect(cell.status).toBe("queued");
|
|
1391
|
-
expect(cell.stopped).toBe(true);
|
|
1392
574
|
expect(cell).toMatchSnapshot("queued after stop");
|
|
1393
575
|
|
|
1394
576
|
// Receive running message
|
|
@@ -1397,12 +579,9 @@ describe("cell reducer", () => {
|
|
|
1397
579
|
output: undefined,
|
|
1398
580
|
console: null,
|
|
1399
581
|
status: "running",
|
|
1400
|
-
stale_inputs: null,
|
|
1401
582
|
timestamp: new Date(40).getTime() as Seconds,
|
|
1402
583
|
});
|
|
1403
584
|
cell = cells[0];
|
|
1404
|
-
expect(cell.status).toBe("running");
|
|
1405
|
-
expect(cell.stopped).toBe(false);
|
|
1406
585
|
expect(cell.output).toBe(null);
|
|
1407
586
|
expect(cell).toMatchSnapshot("running after stop");
|
|
1408
587
|
});
|
|
@@ -1429,7 +608,6 @@ describe("cell reducer", () => {
|
|
|
1429
608
|
|
|
1430
609
|
// Initial state
|
|
1431
610
|
let cell = cells[0];
|
|
1432
|
-
expect(cell.status).toBe("idle");
|
|
1433
611
|
expect(cell.consoleOutputs).toEqual([]);
|
|
1434
612
|
expect(cell).toMatchSnapshot("initial state");
|
|
1435
613
|
|
|
@@ -1438,7 +616,6 @@ describe("cell reducer", () => {
|
|
|
1438
616
|
cellId: firstCellId,
|
|
1439
617
|
});
|
|
1440
618
|
cell = cells[0];
|
|
1441
|
-
expect(cell.status).toBe("queued");
|
|
1442
619
|
expect(cell.consoleOutputs).toEqual([]);
|
|
1443
620
|
expect(cell).toMatchSnapshot("prepared for run");
|
|
1444
621
|
|
|
@@ -1448,11 +625,9 @@ describe("cell reducer", () => {
|
|
|
1448
625
|
output: undefined,
|
|
1449
626
|
console: null,
|
|
1450
627
|
status: "queued",
|
|
1451
|
-
stale_inputs: null,
|
|
1452
628
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1453
629
|
});
|
|
1454
630
|
cell = cells[0];
|
|
1455
|
-
expect(cell.status).toBe("queued");
|
|
1456
631
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1457
632
|
|
|
1458
633
|
// Receive running messages
|
|
@@ -1461,11 +636,9 @@ describe("cell reducer", () => {
|
|
|
1461
636
|
output: undefined,
|
|
1462
637
|
console: null,
|
|
1463
638
|
status: "running",
|
|
1464
|
-
stale_inputs: null,
|
|
1465
639
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1466
640
|
});
|
|
1467
641
|
cell = cells[0];
|
|
1468
|
-
expect(cell.status).toBe("running");
|
|
1469
642
|
expect(cell).toMatchSnapshot("running message received");
|
|
1470
643
|
|
|
1471
644
|
// Add console
|
|
@@ -1474,16 +647,13 @@ describe("cell reducer", () => {
|
|
|
1474
647
|
output: undefined,
|
|
1475
648
|
console: STDOUT,
|
|
1476
649
|
status: undefined,
|
|
1477
|
-
stale_inputs: null,
|
|
1478
650
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1479
651
|
});
|
|
1480
652
|
cell = cells[0];
|
|
1481
|
-
expect(cell.status).toBe("running");
|
|
1482
653
|
expect(cell).toMatchSnapshot("stdout received");
|
|
1483
654
|
|
|
1484
655
|
cell = cells[0];
|
|
1485
656
|
expect(cell.consoleOutputs[0]).toMatchObject(STDOUT);
|
|
1486
|
-
expect(cell.status).toBe("running");
|
|
1487
657
|
expect(cell).toMatchSnapshot("stdout verified");
|
|
1488
658
|
|
|
1489
659
|
// Ask via stdin
|
|
@@ -1492,13 +662,11 @@ describe("cell reducer", () => {
|
|
|
1492
662
|
output: undefined,
|
|
1493
663
|
console: STD_IN_1,
|
|
1494
664
|
status: undefined,
|
|
1495
|
-
stale_inputs: null,
|
|
1496
665
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1497
666
|
});
|
|
1498
667
|
cell = cells[0];
|
|
1499
668
|
expect(cell.consoleOutputs[0]).toMatchObject(STDOUT);
|
|
1500
669
|
expect(cell.consoleOutputs[1]).toMatchObject(STD_IN_1);
|
|
1501
|
-
expect(cell.status).toBe("running");
|
|
1502
670
|
expect(cell).toMatchSnapshot("stdin requested");
|
|
1503
671
|
|
|
1504
672
|
// Response to stdin
|
|
@@ -1512,7 +680,6 @@ describe("cell reducer", () => {
|
|
|
1512
680
|
...STD_IN_1,
|
|
1513
681
|
response: "Marimo!",
|
|
1514
682
|
});
|
|
1515
|
-
expect(cell.status).toBe("running");
|
|
1516
683
|
expect(cell).toMatchSnapshot("stdin answered");
|
|
1517
684
|
|
|
1518
685
|
// Ask via stdin, again
|
|
@@ -1521,7 +688,6 @@ describe("cell reducer", () => {
|
|
|
1521
688
|
output: undefined,
|
|
1522
689
|
console: STD_IN_2,
|
|
1523
690
|
status: undefined,
|
|
1524
|
-
stale_inputs: null,
|
|
1525
691
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1526
692
|
});
|
|
1527
693
|
cell = cells[0];
|
|
@@ -1530,7 +696,6 @@ describe("cell reducer", () => {
|
|
|
1530
696
|
{ ...STD_IN_1, response: "Marimo!" },
|
|
1531
697
|
STD_IN_2,
|
|
1532
698
|
]);
|
|
1533
|
-
expect(cell.status).toBe("running");
|
|
1534
699
|
expect(cell).toMatchSnapshot("second stdin requested");
|
|
1535
700
|
|
|
1536
701
|
// Interrupt, so we respond with ""
|
|
@@ -1544,11 +709,9 @@ describe("cell reducer", () => {
|
|
|
1544
709
|
},
|
|
1545
710
|
console: null,
|
|
1546
711
|
status: "idle",
|
|
1547
|
-
stale_inputs: null,
|
|
1548
712
|
timestamp: new Date(61).getTime() as Seconds,
|
|
1549
713
|
});
|
|
1550
714
|
cell = cells[0];
|
|
1551
|
-
expect(cell.status).toBe("idle");
|
|
1552
715
|
expect(cell.consoleOutputs).toMatchObject([
|
|
1553
716
|
STDOUT,
|
|
1554
717
|
{ ...STD_IN_1, response: "Marimo!" },
|
|
@@ -1568,7 +731,6 @@ describe("cell reducer", () => {
|
|
|
1568
731
|
output: undefined,
|
|
1569
732
|
console: prompt,
|
|
1570
733
|
status: "running",
|
|
1571
|
-
stale_inputs: null,
|
|
1572
734
|
timestamp: 1 as Seconds,
|
|
1573
735
|
});
|
|
1574
736
|
|
|
@@ -1579,7 +741,9 @@ describe("cell reducer", () => {
|
|
|
1579
741
|
response: secret,
|
|
1580
742
|
});
|
|
1581
743
|
|
|
1582
|
-
expect(cells[0].consoleOutputs).toEqual([
|
|
744
|
+
expect(cells[0].consoleOutputs).toEqual([
|
|
745
|
+
{ ...prompt, id: 1, response: "" },
|
|
746
|
+
]);
|
|
1583
747
|
expect(JSON.stringify(cells[0].consoleOutputs)).not.toContain(secret);
|
|
1584
748
|
});
|
|
1585
749
|
|
|
@@ -1598,7 +762,6 @@ describe("cell reducer", () => {
|
|
|
1598
762
|
output: undefined,
|
|
1599
763
|
console: null,
|
|
1600
764
|
status: "running",
|
|
1601
|
-
stale_inputs: null,
|
|
1602
765
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1603
766
|
});
|
|
1604
767
|
actions.handleCellMessage({
|
|
@@ -1606,7 +769,6 @@ describe("cell reducer", () => {
|
|
|
1606
769
|
output: undefined,
|
|
1607
770
|
console: STDOUT,
|
|
1608
771
|
status: undefined,
|
|
1609
|
-
stale_inputs: null,
|
|
1610
772
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1611
773
|
});
|
|
1612
774
|
|
|
@@ -1640,7 +802,6 @@ describe("cell reducer", () => {
|
|
|
1640
802
|
|
|
1641
803
|
// Initial state
|
|
1642
804
|
let cell = cells[0];
|
|
1643
|
-
expect(cell.status).toBe("idle");
|
|
1644
805
|
expect(cell.consoleOutputs).toEqual([]);
|
|
1645
806
|
expect(cell).toMatchSnapshot("initial state");
|
|
1646
807
|
|
|
@@ -1650,7 +811,6 @@ describe("cell reducer", () => {
|
|
|
1650
811
|
output: undefined,
|
|
1651
812
|
console: [OLD_STDOUT],
|
|
1652
813
|
status: undefined,
|
|
1653
|
-
stale_inputs: null,
|
|
1654
814
|
timestamp: new Date(1).getTime() as Seconds,
|
|
1655
815
|
});
|
|
1656
816
|
|
|
@@ -1659,7 +819,6 @@ describe("cell reducer", () => {
|
|
|
1659
819
|
cellId: firstCellId,
|
|
1660
820
|
});
|
|
1661
821
|
cell = cells[0];
|
|
1662
|
-
expect(cell.status).toBe("queued");
|
|
1663
822
|
expect(cell.consoleOutputs).toMatchObject([OLD_STDOUT]); // Old stays there until it starts running
|
|
1664
823
|
expect(cell).toMatchSnapshot("prepared for run");
|
|
1665
824
|
|
|
@@ -1669,11 +828,9 @@ describe("cell reducer", () => {
|
|
|
1669
828
|
output: undefined,
|
|
1670
829
|
console: null,
|
|
1671
830
|
status: "queued",
|
|
1672
|
-
stale_inputs: null,
|
|
1673
831
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1674
832
|
});
|
|
1675
833
|
cell = cells[0];
|
|
1676
|
-
expect(cell.status).toBe("queued");
|
|
1677
834
|
expect(cell.consoleOutputs).toMatchObject([OLD_STDOUT]); // Old stays there until it starts running
|
|
1678
835
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1679
836
|
|
|
@@ -1683,624 +840,50 @@ describe("cell reducer", () => {
|
|
|
1683
840
|
output: undefined,
|
|
1684
841
|
console: [], // Backend sends an empty array to clearu
|
|
1685
842
|
status: "running",
|
|
1686
|
-
stale_inputs: null,
|
|
1687
843
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1688
844
|
});
|
|
1689
845
|
cell = cells[0];
|
|
1690
|
-
expect(cell.status).toBe("running");
|
|
1691
846
|
expect(cell.consoleOutputs).toMatchObject([]);
|
|
1692
847
|
expect(cell).toMatchSnapshot("console cleared while running");
|
|
1693
848
|
|
|
1694
849
|
// Add console
|
|
1695
850
|
actions.handleCellMessage({
|
|
1696
|
-
cell_id: firstCellId,
|
|
1697
|
-
output: undefined,
|
|
1698
|
-
console: [STDOUT],
|
|
1699
|
-
status: "idle",
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
cell
|
|
1704
|
-
expect(cell
|
|
1705
|
-
expect(cell.status).toBe("idle");
|
|
1706
|
-
expect(cell).toMatchSnapshot("console received while idle");
|
|
1707
|
-
});
|
|
1708
|
-
|
|
1709
|
-
it("can send a cell to the top", () => {
|
|
1710
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
1711
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
1712
|
-
actions.sendToTop({ cellId: cellId("2") });
|
|
1713
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
1714
|
-
"
|
|
1715
|
-
[2] ''
|
|
1716
|
-
|
|
1717
|
-
[0] ''
|
|
1718
|
-
|
|
1719
|
-
[1] ''
|
|
1720
|
-
"
|
|
1721
|
-
`);
|
|
1722
|
-
});
|
|
1723
|
-
|
|
1724
|
-
it("can send a cell to the bottom", () => {
|
|
1725
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
1726
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
1727
|
-
actions.sendToBottom({ cellId: firstCellId });
|
|
1728
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
1729
|
-
"
|
|
1730
|
-
[1] ''
|
|
1731
|
-
|
|
1732
|
-
[2] ''
|
|
1733
|
-
|
|
1734
|
-
[0] ''
|
|
1735
|
-
"
|
|
1736
|
-
`);
|
|
1737
|
-
});
|
|
1738
|
-
|
|
1739
|
-
it("can focus cells", () => {
|
|
1740
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
1741
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
1742
|
-
|
|
1743
|
-
actions.focusCell({ cellId: cellId("1"), where: "before" });
|
|
1744
|
-
expect(focusAndScrollCellIntoView).toHaveBeenCalledWith(
|
|
1745
|
-
expect.objectContaining({
|
|
1746
|
-
cellId: cellId("0"),
|
|
1747
|
-
}),
|
|
1748
|
-
);
|
|
1749
|
-
|
|
1750
|
-
actions.focusTopCell();
|
|
1751
|
-
expect(scrollToTop).toHaveBeenCalled();
|
|
1752
|
-
|
|
1753
|
-
actions.focusBottomCell();
|
|
1754
|
-
expect(scrollToBottom).toHaveBeenCalled();
|
|
1755
|
-
});
|
|
1756
|
-
|
|
1757
|
-
it("can update cell name", () => {
|
|
1758
|
-
actions.updateCellName({ cellId: firstCellId, name: "Test Cell" });
|
|
1759
|
-
expect(state.cellData[firstCellId].name).toBe("Test Cell");
|
|
1760
|
-
});
|
|
1761
|
-
|
|
1762
|
-
it("can set cell IDs and codes", () => {
|
|
1763
|
-
const newIds = [cellId("3"), cellId("4"), cellId("5")];
|
|
1764
|
-
const newCodes = ["code1", "code2", "code3"];
|
|
1765
|
-
|
|
1766
|
-
actions.setCellIds({ cellIds: newIds });
|
|
1767
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).topLevelIds).toEqual(newIds);
|
|
1768
|
-
|
|
1769
|
-
// When codeIsStale is false, lastCodeRun should match code
|
|
1770
|
-
actions.setCellCodes({
|
|
1771
|
-
codes: newCodes,
|
|
1772
|
-
ids: newIds,
|
|
1773
|
-
codeIsStale: false,
|
|
1774
|
-
});
|
|
1775
|
-
newIds.forEach((id, index) => {
|
|
1776
|
-
expect(state.cellData[id].code).toBe(newCodes[index]);
|
|
1777
|
-
expect(state.cellData[id].lastCodeRun).toBe(newCodes[index]);
|
|
1778
|
-
expect(state.cellData[id].edited).toBe(false);
|
|
1779
|
-
});
|
|
1780
|
-
|
|
1781
|
-
// When codeIsStale is true, lastCodeRun should not change
|
|
1782
|
-
const staleCodes = ["stale1", "stale2", "stale3"];
|
|
1783
|
-
actions.setCellCodes({
|
|
1784
|
-
codes: staleCodes,
|
|
1785
|
-
ids: newIds,
|
|
1786
|
-
codeIsStale: true,
|
|
1787
|
-
});
|
|
1788
|
-
newIds.forEach((id, index) => {
|
|
1789
|
-
expect(state.cellData[id].code).toBe(staleCodes[index]);
|
|
1790
|
-
expect(state.cellData[id].lastCodeRun).toBe(newCodes[index]);
|
|
1791
|
-
expect(state.cellData[id].edited).toBe(true);
|
|
1792
|
-
});
|
|
1793
|
-
});
|
|
1794
|
-
|
|
1795
|
-
it("can can add a new cell with/without stale code", () => {
|
|
1796
|
-
actions.setCellCodes({
|
|
1797
|
-
codes: ["new code"],
|
|
1798
|
-
ids: [cellId("2")],
|
|
1799
|
-
codeIsStale: false,
|
|
1800
|
-
});
|
|
1801
|
-
|
|
1802
|
-
expect(state.cellData[cellId("2")].code).toBe("new code");
|
|
1803
|
-
expect(state.cellData[cellId("2")].edited).toBe(false);
|
|
1804
|
-
expect(state.cellData[cellId("2")].lastCodeRun).toBe("new code");
|
|
1805
|
-
|
|
1806
|
-
actions.setCellCodes({
|
|
1807
|
-
codes: ["new code 2"],
|
|
1808
|
-
ids: [cellId("9")],
|
|
1809
|
-
codeIsStale: true,
|
|
1810
|
-
});
|
|
1811
|
-
|
|
1812
|
-
expect(state.cellData[cellId("9")].code).toBe("new code 2");
|
|
1813
|
-
expect(state.cellData[cellId("9")].edited).toBe(true);
|
|
1814
|
-
expect(state.cellData[cellId("9")].lastCodeRun).toBe(null);
|
|
1815
|
-
});
|
|
1816
|
-
|
|
1817
|
-
it("can partial update cell codes", () => {
|
|
1818
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
1819
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
1820
|
-
|
|
1821
|
-
expect(state.cellIds.inOrderIds).toEqual([
|
|
1822
|
-
cellId("0"),
|
|
1823
|
-
cellId("1"),
|
|
1824
|
-
cellId("2"),
|
|
1825
|
-
]);
|
|
1826
|
-
expect(state.cellData[cellId("0")].code).toBe("");
|
|
1827
|
-
expect(state.cellData[cellId("1")].code).toBe("");
|
|
1828
|
-
expect(state.cellData[cellId("2")].code).toBe("");
|
|
1829
|
-
|
|
1830
|
-
// Update cell 1
|
|
1831
|
-
actions.setCellCodes({
|
|
1832
|
-
codes: ["new code 2"],
|
|
1833
|
-
ids: [cellId("1")],
|
|
1834
|
-
codeIsStale: false,
|
|
1835
|
-
});
|
|
1836
|
-
|
|
1837
|
-
expect(state.cellIds.inOrderIds).toEqual([
|
|
1838
|
-
cellId("0"),
|
|
1839
|
-
cellId("1"),
|
|
1840
|
-
cellId("2"),
|
|
1841
|
-
]);
|
|
1842
|
-
expect(state.cellData[cellId("0")].code).toBe("");
|
|
1843
|
-
expect(state.cellData[cellId("1")].code).toBe("new code 2");
|
|
1844
|
-
expect(state.cellData[cellId("1")].edited).toBe(false);
|
|
1845
|
-
expect(state.cellData[cellId("2")].code).toBe("");
|
|
1846
|
-
});
|
|
1847
|
-
|
|
1848
|
-
it("can set cell codes with new cell ids, while preserving the old cell data", () => {
|
|
1849
|
-
actions.setCellCodes({
|
|
1850
|
-
codes: ["code1", "code2", "code3"],
|
|
1851
|
-
ids: [cellId("3"), cellId("4"), cellId("5")],
|
|
1852
|
-
codeIsStale: false,
|
|
1853
|
-
});
|
|
1854
|
-
expect(state.cellData[cellId("3")].code).toBe("code1");
|
|
1855
|
-
expect(state.cellData[cellId("4")].code).toBe("code2");
|
|
1856
|
-
expect(state.cellData[cellId("5")].code).toBe("code3");
|
|
1857
|
-
|
|
1858
|
-
// Update with some new cell ids and some old cell ids
|
|
1859
|
-
actions.setCellIds({
|
|
1860
|
-
cellIds: [cellId("1"), cellId("2"), cellId("3"), cellId("4")],
|
|
1861
|
-
});
|
|
1862
|
-
actions.setCellCodes({
|
|
1863
|
-
codes: ["new1", "new2", "code1", "code2"],
|
|
1864
|
-
ids: [cellId("1"), cellId("2"), cellId("3"), cellId("4")],
|
|
1865
|
-
codeIsStale: false,
|
|
1866
|
-
});
|
|
1867
|
-
expect(state.cellData[cellId("1")].code).toBe("new1");
|
|
1868
|
-
expect(state.cellData[cellId("2")].code).toBe("new2");
|
|
1869
|
-
expect(state.cellData[cellId("3")].code).toBe("code1");
|
|
1870
|
-
expect(state.cellData[cellId("4")].code).toBe("code2");
|
|
1871
|
-
expect(state.cellIds.inOrderIds).toEqual([
|
|
1872
|
-
cellId("1"),
|
|
1873
|
-
cellId("2"),
|
|
1874
|
-
cellId("3"),
|
|
1875
|
-
cellId("4"),
|
|
1876
|
-
]);
|
|
1877
|
-
// Cell 5 data is preserved (possibly used for tracing), but it's not in the cellIds
|
|
1878
|
-
expect(state.cellData[cellId("5")]).not.toBeUndefined();
|
|
1879
|
-
});
|
|
1880
|
-
|
|
1881
|
-
it("can set cell codes with names and configs", () => {
|
|
1882
|
-
const newIds = [cellId("3"), cellId("4")];
|
|
1883
|
-
actions.setCellIds({ cellIds: newIds });
|
|
1884
|
-
actions.setCellCodes({
|
|
1885
|
-
codes: ["code1", "code2"],
|
|
1886
|
-
ids: newIds,
|
|
1887
|
-
codeIsStale: false,
|
|
1888
|
-
names: ["setup_cell", "analysis"],
|
|
1889
|
-
configs: [
|
|
1890
|
-
{ hide_code: true, disabled: false, column: null },
|
|
1891
|
-
{ hide_code: false, disabled: true, column: null },
|
|
1892
|
-
],
|
|
1893
|
-
});
|
|
1894
|
-
|
|
1895
|
-
expect(state.cellData[cellId("3")].name).toBe("setup_cell");
|
|
1896
|
-
expect(state.cellData[cellId("3")].config.hide_code).toBe(true);
|
|
1897
|
-
expect(state.cellData[cellId("3")].config.disabled).toBe(false);
|
|
1898
|
-
|
|
1899
|
-
expect(state.cellData[cellId("4")].name).toBe("analysis");
|
|
1900
|
-
expect(state.cellData[cellId("4")].config.hide_code).toBe(false);
|
|
1901
|
-
expect(state.cellData[cellId("4")].config.disabled).toBe(true);
|
|
1902
|
-
});
|
|
1903
|
-
|
|
1904
|
-
it("can set cell codes without names/configs (backward compat)", () => {
|
|
1905
|
-
const newIds = [cellId("3")];
|
|
1906
|
-
actions.setCellIds({ cellIds: newIds });
|
|
1907
|
-
actions.setCellCodes({
|
|
1908
|
-
codes: ["code1"],
|
|
1909
|
-
ids: newIds,
|
|
1910
|
-
codeIsStale: false,
|
|
1911
|
-
});
|
|
1912
|
-
|
|
1913
|
-
// Should use defaults when names/configs not provided
|
|
1914
|
-
expect(state.cellData[cellId("3")].code).toBe("code1");
|
|
1915
|
-
expect(state.cellData[cellId("3")].config.hide_code).toBe(false);
|
|
1916
|
-
expect(state.cellData[cellId("3")].config.disabled).toBe(false);
|
|
1917
|
-
});
|
|
1918
|
-
|
|
1919
|
-
it("can update names and configs on existing cells via setCellCodes", () => {
|
|
1920
|
-
// Set initial state
|
|
1921
|
-
actions.setCellCodes({
|
|
1922
|
-
codes: ["x = 1"],
|
|
1923
|
-
ids: [firstCellId],
|
|
1924
|
-
codeIsStale: false,
|
|
1925
|
-
names: ["old_name"],
|
|
1926
|
-
configs: [{ hide_code: false, disabled: false, column: null }],
|
|
1927
|
-
});
|
|
1928
|
-
expect(state.cellData[firstCellId].name).toBe("old_name");
|
|
1929
|
-
expect(state.cellData[firstCellId].config.hide_code).toBe(false);
|
|
1930
|
-
|
|
1931
|
-
// Update with new name and config (same code)
|
|
1932
|
-
actions.setCellCodes({
|
|
1933
|
-
codes: ["x = 1"],
|
|
1934
|
-
ids: [firstCellId],
|
|
1935
|
-
codeIsStale: true,
|
|
1936
|
-
names: ["new_name"],
|
|
1937
|
-
configs: [{ hide_code: true, disabled: false, column: null }],
|
|
1938
|
-
});
|
|
1939
|
-
expect(state.cellData[firstCellId].name).toBe("new_name");
|
|
1940
|
-
expect(state.cellData[firstCellId].config.hide_code).toBe(true);
|
|
1941
|
-
});
|
|
1942
|
-
|
|
1943
|
-
it("can fold and unfold all cells", () => {
|
|
1944
|
-
actions.foldAll();
|
|
1945
|
-
expect(foldAllBulk).toHaveBeenCalled();
|
|
1946
|
-
|
|
1947
|
-
actions.unfoldAll();
|
|
1948
|
-
expect(unfoldAllBulk).toHaveBeenCalled();
|
|
1949
|
-
});
|
|
1950
|
-
|
|
1951
|
-
it("can clear logs", () => {
|
|
1952
|
-
state.cellLogs = [
|
|
1953
|
-
{
|
|
1954
|
-
level: "stderr",
|
|
1955
|
-
message: "log1",
|
|
1956
|
-
timestamp: 0,
|
|
1957
|
-
source: { type: "cell", cellId: firstCellId },
|
|
1958
|
-
},
|
|
1959
|
-
{
|
|
1960
|
-
level: "stderr",
|
|
1961
|
-
message: "log1",
|
|
1962
|
-
timestamp: 0,
|
|
1963
|
-
source: { type: "cell", cellId: firstCellId },
|
|
1964
|
-
},
|
|
1965
|
-
];
|
|
1966
|
-
actions.clearLogs();
|
|
1967
|
-
expect(state.cellLogs).toEqual([]);
|
|
1968
|
-
});
|
|
1969
|
-
|
|
1970
|
-
it("can collapse and expand cells", () => {
|
|
1971
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
1972
|
-
actions.createNewCell({
|
|
1973
|
-
cellId: cellId("1"),
|
|
1974
|
-
before: false,
|
|
1975
|
-
code: "# Header",
|
|
1976
|
-
});
|
|
1977
|
-
actions.createNewCell({
|
|
1978
|
-
cellId: cellId("2"),
|
|
1979
|
-
before: false,
|
|
1980
|
-
code: "## Subheader",
|
|
1981
|
-
});
|
|
1982
|
-
|
|
1983
|
-
const id = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(1);
|
|
1984
|
-
state.cellRuntime[id] = {
|
|
1985
|
-
...state.cellRuntime[id],
|
|
1986
|
-
outline: {
|
|
1987
|
-
items: [{ name: "Header", level: 1, by: { id: "header" } }],
|
|
1988
|
-
},
|
|
1989
|
-
};
|
|
1990
|
-
|
|
1991
|
-
actions.collapseCell({ cellId: id });
|
|
1992
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(id)).toBe(true);
|
|
1993
|
-
|
|
1994
|
-
actions.expandCell({ cellId: id });
|
|
1995
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(id)).toBe(false);
|
|
1996
|
-
});
|
|
1997
|
-
|
|
1998
|
-
it("can collapse and expand all cells in multiple columns", () => {
|
|
1999
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2000
|
-
actions.createNewCell({
|
|
2001
|
-
cellId: cellId("1"),
|
|
2002
|
-
before: false,
|
|
2003
|
-
code: "# First Column Header",
|
|
2004
|
-
});
|
|
2005
|
-
actions.createNewCell({
|
|
2006
|
-
cellId: cellId("2"),
|
|
2007
|
-
before: false,
|
|
2008
|
-
code: "## First Column Subheader",
|
|
2009
|
-
});
|
|
2010
|
-
|
|
2011
|
-
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2012
|
-
|
|
2013
|
-
actions.createNewCell({
|
|
2014
|
-
cellId: cellId("3"),
|
|
2015
|
-
before: false,
|
|
2016
|
-
code: "# Second Column Header",
|
|
2017
|
-
});
|
|
2018
|
-
actions.createNewCell({
|
|
2019
|
-
cellId: cellId("4"),
|
|
2020
|
-
before: false,
|
|
2021
|
-
code: "## Second Column Subheader",
|
|
2022
|
-
});
|
|
2023
|
-
|
|
2024
|
-
const firstColumnHeaderId = state.cellIds
|
|
2025
|
-
.atOrThrow(FIRST_COLUMN)
|
|
2026
|
-
.atOrThrow(1);
|
|
2027
|
-
state.cellRuntime[firstColumnHeaderId] = {
|
|
2028
|
-
...state.cellRuntime[firstColumnHeaderId],
|
|
2029
|
-
outline: {
|
|
2030
|
-
items: [
|
|
2031
|
-
{ name: "First Column Header", level: 1, by: { id: "header" } },
|
|
2032
|
-
],
|
|
2033
|
-
},
|
|
2034
|
-
};
|
|
2035
|
-
|
|
2036
|
-
const secondColumnHeaderId = state.cellIds
|
|
2037
|
-
.atOrThrow(SECOND_COLUMN)
|
|
2038
|
-
.atOrThrow(0);
|
|
2039
|
-
state.cellRuntime[secondColumnHeaderId] = {
|
|
2040
|
-
...state.cellRuntime[secondColumnHeaderId],
|
|
2041
|
-
outline: {
|
|
2042
|
-
items: [
|
|
2043
|
-
{ name: "Second Column Header", level: 1, by: { id: "header" } },
|
|
2044
|
-
],
|
|
2045
|
-
},
|
|
2046
|
-
};
|
|
2047
|
-
|
|
2048
|
-
actions.collapseAllCells();
|
|
2049
|
-
expect(
|
|
2050
|
-
state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(firstColumnHeaderId),
|
|
2051
|
-
).toBe(true);
|
|
2052
|
-
expect(
|
|
2053
|
-
state.cellIds.atOrThrow(SECOND_COLUMN).isCollapsed(secondColumnHeaderId),
|
|
2054
|
-
).toBe(true);
|
|
2055
|
-
|
|
2056
|
-
actions.expandAllCells();
|
|
2057
|
-
expect(
|
|
2058
|
-
state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(firstColumnHeaderId),
|
|
2059
|
-
).toBe(false);
|
|
2060
|
-
expect(
|
|
2061
|
-
state.cellIds.atOrThrow(SECOND_COLUMN).isCollapsed(secondColumnHeaderId),
|
|
2062
|
-
).toBe(false);
|
|
2063
|
-
});
|
|
2064
|
-
|
|
2065
|
-
it("can collapse and expand nested cells in one call", () => {
|
|
2066
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2067
|
-
actions.createNewCell({
|
|
2068
|
-
cellId: cellId("1"),
|
|
2069
|
-
before: false,
|
|
2070
|
-
code: "# Header",
|
|
2071
|
-
});
|
|
2072
|
-
actions.createNewCell({
|
|
2073
|
-
cellId: cellId("2"),
|
|
2074
|
-
before: false,
|
|
2075
|
-
code: "## Subheader",
|
|
2076
|
-
});
|
|
2077
|
-
actions.createNewCell({
|
|
2078
|
-
cellId: cellId("3"),
|
|
2079
|
-
before: false,
|
|
2080
|
-
code: "### Subsubheader",
|
|
2081
|
-
});
|
|
2082
|
-
|
|
2083
|
-
const headerId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(1);
|
|
2084
|
-
state.cellRuntime[headerId] = {
|
|
2085
|
-
...state.cellRuntime[headerId],
|
|
2086
|
-
outline: {
|
|
2087
|
-
items: [{ name: "Header", level: 1, by: { id: "header" } }],
|
|
2088
|
-
},
|
|
2089
|
-
};
|
|
2090
|
-
|
|
2091
|
-
const subheaderId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(2);
|
|
2092
|
-
state.cellRuntime[subheaderId] = {
|
|
2093
|
-
...state.cellRuntime[subheaderId],
|
|
2094
|
-
outline: {
|
|
2095
|
-
items: [{ name: "Subheader", level: 2, by: { id: "subheader" } }],
|
|
2096
|
-
},
|
|
2097
|
-
};
|
|
2098
|
-
|
|
2099
|
-
// Check if both the parent and child are collapsed
|
|
2100
|
-
actions.collapseAllCells();
|
|
2101
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(headerId)).toBe(
|
|
2102
|
-
true,
|
|
2103
|
-
);
|
|
2104
|
-
actions.expandCell({ cellId: headerId });
|
|
2105
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(subheaderId)).toBe(
|
|
2106
|
-
true,
|
|
2107
|
-
);
|
|
2108
|
-
actions.collapseCell({ cellId: headerId });
|
|
2109
|
-
|
|
2110
|
-
// Check if both the parent and child are expanded
|
|
2111
|
-
actions.expandAllCells();
|
|
2112
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(headerId)).toBe(
|
|
2113
|
-
false,
|
|
2114
|
-
);
|
|
2115
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(subheaderId)).toBe(
|
|
2116
|
-
false,
|
|
2117
|
-
);
|
|
2118
|
-
});
|
|
2119
|
-
|
|
2120
|
-
it("can collapse all cells when nested heading ranges end at the same cell", () => {
|
|
2121
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2122
|
-
actions.createNewCell({
|
|
2123
|
-
cellId: cellId("1"),
|
|
2124
|
-
before: false,
|
|
2125
|
-
code: "# Header",
|
|
2126
|
-
});
|
|
2127
|
-
actions.createNewCell({
|
|
2128
|
-
cellId: cellId("2"),
|
|
2129
|
-
before: false,
|
|
2130
|
-
code: "## Subheader",
|
|
2131
|
-
});
|
|
2132
|
-
actions.createNewCell({
|
|
2133
|
-
cellId: cellId("3"),
|
|
2134
|
-
before: false,
|
|
2135
|
-
code: "### Subsubheader",
|
|
2136
|
-
});
|
|
2137
|
-
|
|
2138
|
-
const headerId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(1);
|
|
2139
|
-
state.cellRuntime[headerId] = {
|
|
2140
|
-
...state.cellRuntime[headerId],
|
|
2141
|
-
outline: {
|
|
2142
|
-
items: [{ name: "Header", level: 1, by: { id: "header" } }],
|
|
2143
|
-
},
|
|
2144
|
-
};
|
|
2145
|
-
|
|
2146
|
-
const subheaderId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(2);
|
|
2147
|
-
state.cellRuntime[subheaderId] = {
|
|
2148
|
-
...state.cellRuntime[subheaderId],
|
|
2149
|
-
outline: {
|
|
2150
|
-
items: [{ name: "Subheader", level: 2, by: { id: "subheader" } }],
|
|
2151
|
-
},
|
|
2152
|
-
};
|
|
2153
|
-
|
|
2154
|
-
const subsubheaderId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(3);
|
|
2155
|
-
state.cellRuntime[subsubheaderId] = {
|
|
2156
|
-
...state.cellRuntime[subsubheaderId],
|
|
2157
|
-
outline: {
|
|
2158
|
-
items: [{ name: "Subsubheader", level: 3, by: { id: "subsubheader" } }],
|
|
2159
|
-
},
|
|
2160
|
-
};
|
|
2161
|
-
|
|
2162
|
-
// The header, subheader and subsubheader ranges all end at the last
|
|
2163
|
-
// cell. Collapsing all used to throw "Node ... not found in tree" and
|
|
2164
|
-
// leave the whole notebook unchanged.
|
|
2165
|
-
actions.collapseAllCells();
|
|
2166
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(headerId)).toBe(
|
|
2167
|
-
true,
|
|
2168
|
-
);
|
|
2169
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).topLevelIds).toEqual([
|
|
2170
|
-
firstCellId,
|
|
2171
|
-
headerId,
|
|
2172
|
-
]);
|
|
2173
|
-
|
|
2174
|
-
// Each level is nested under its parent, collapsed
|
|
2175
|
-
actions.expandCell({ cellId: headerId });
|
|
2176
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(subheaderId)).toBe(
|
|
2177
|
-
true,
|
|
2178
|
-
);
|
|
2179
|
-
actions.expandCell({ cellId: subheaderId });
|
|
2180
|
-
expect(
|
|
2181
|
-
state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(subsubheaderId),
|
|
2182
|
-
).toBe(true);
|
|
2183
|
-
});
|
|
2184
|
-
|
|
2185
|
-
it("can collapse all cells when a deep chain is followed by a later section", () => {
|
|
2186
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2187
|
-
actions.createNewCell({
|
|
2188
|
-
cellId: cellId("1"),
|
|
2189
|
-
before: false,
|
|
2190
|
-
code: "# Header",
|
|
2191
|
-
});
|
|
2192
|
-
actions.createNewCell({
|
|
2193
|
-
cellId: cellId("2"),
|
|
2194
|
-
before: false,
|
|
2195
|
-
code: "## Section A",
|
|
2196
|
-
});
|
|
2197
|
-
actions.createNewCell({
|
|
2198
|
-
cellId: cellId("3"),
|
|
2199
|
-
before: false,
|
|
2200
|
-
code: "### Sub of A",
|
|
2201
|
-
});
|
|
2202
|
-
actions.createNewCell({
|
|
2203
|
-
cellId: cellId("4"),
|
|
2204
|
-
before: false,
|
|
2205
|
-
code: "## Section B",
|
|
2206
|
-
});
|
|
2207
|
-
|
|
2208
|
-
const headerId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(1);
|
|
2209
|
-
state.cellRuntime[headerId] = {
|
|
2210
|
-
...state.cellRuntime[headerId],
|
|
2211
|
-
outline: {
|
|
2212
|
-
items: [{ name: "Header", level: 1, by: { id: "header" } }],
|
|
2213
|
-
},
|
|
2214
|
-
};
|
|
2215
|
-
|
|
2216
|
-
const sectionAId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(2);
|
|
2217
|
-
state.cellRuntime[sectionAId] = {
|
|
2218
|
-
...state.cellRuntime[sectionAId],
|
|
2219
|
-
outline: {
|
|
2220
|
-
items: [{ name: "Section A", level: 2, by: { id: "section-a" } }],
|
|
2221
|
-
},
|
|
2222
|
-
};
|
|
2223
|
-
|
|
2224
|
-
const subsectionId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(3);
|
|
2225
|
-
state.cellRuntime[subsectionId] = {
|
|
2226
|
-
...state.cellRuntime[subsectionId],
|
|
2227
|
-
outline: {
|
|
2228
|
-
items: [{ name: "Sub of A", level: 3, by: { id: "sub-of-a" } }],
|
|
2229
|
-
},
|
|
2230
|
-
};
|
|
2231
|
-
|
|
2232
|
-
const sectionBId = state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(4);
|
|
2233
|
-
state.cellRuntime[sectionBId] = {
|
|
2234
|
-
...state.cellRuntime[sectionBId],
|
|
2235
|
-
outline: {
|
|
2236
|
-
items: [{ name: "Section B", level: 2, by: { id: "section-b" } }],
|
|
2237
|
-
},
|
|
2238
|
-
};
|
|
2239
|
-
|
|
2240
|
-
actions.collapseAllCells();
|
|
2241
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(headerId)).toBe(
|
|
2242
|
-
true,
|
|
2243
|
-
);
|
|
2244
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).topLevelIds).toEqual([
|
|
2245
|
-
firstCellId,
|
|
2246
|
-
headerId,
|
|
2247
|
-
]);
|
|
2248
|
-
|
|
2249
|
-
// Both sections sit under the header, collapsed, with the subsection
|
|
2250
|
-
// nested under section A
|
|
2251
|
-
actions.expandCell({ cellId: headerId });
|
|
2252
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(sectionAId)).toBe(
|
|
2253
|
-
true,
|
|
2254
|
-
);
|
|
2255
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(sectionBId)).toBe(
|
|
2256
|
-
true,
|
|
2257
|
-
);
|
|
2258
|
-
actions.expandCell({ cellId: sectionAId });
|
|
2259
|
-
expect(
|
|
2260
|
-
state.cellIds.atOrThrow(FIRST_COLUMN).isCollapsed(subsectionId),
|
|
2261
|
-
).toBe(true);
|
|
851
|
+
cell_id: firstCellId,
|
|
852
|
+
output: undefined,
|
|
853
|
+
console: [STDOUT],
|
|
854
|
+
status: "idle",
|
|
855
|
+
timestamp: new Date(22).getTime() as Seconds,
|
|
856
|
+
});
|
|
857
|
+
cell = cells[0];
|
|
858
|
+
expect(cell.consoleOutputs).toMatchObject([STDOUT]);
|
|
859
|
+
expect(cell).toMatchSnapshot("console received while idle");
|
|
2262
860
|
});
|
|
2263
861
|
|
|
2264
|
-
it("can
|
|
2265
|
-
actions.
|
|
2266
|
-
|
|
2267
|
-
actions.collapseCell({ cellId: firstCellId });
|
|
862
|
+
it("can fold and unfold all cells", () => {
|
|
863
|
+
actions.foldAll();
|
|
864
|
+
expect(foldAllBulk).toHaveBeenCalled();
|
|
2268
865
|
|
|
2269
|
-
actions.
|
|
2270
|
-
expect(
|
|
2271
|
-
false,
|
|
2272
|
-
);
|
|
866
|
+
actions.unfoldAll();
|
|
867
|
+
expect(unfoldAllBulk).toHaveBeenCalled();
|
|
2273
868
|
});
|
|
2274
869
|
|
|
2275
|
-
it("can
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
actions.
|
|
2291
|
-
expect(state.
|
|
2292
|
-
originalCellCount + 1,
|
|
2293
|
-
);
|
|
2294
|
-
expect(state.cellData[nextCellId].code).toBe("line1");
|
|
2295
|
-
expect(
|
|
2296
|
-
state.cellData[state.cellIds.atOrThrow(FIRST_COLUMN).atOrThrow(2)].code,
|
|
2297
|
-
).toBe("line2");
|
|
2298
|
-
|
|
2299
|
-
actions.undoSplitCell({ cellId: nextCellId, snapshot: "line1\nline2" });
|
|
2300
|
-
expect(state.cellIds.atOrThrow(FIRST_COLUMN).length).toBe(
|
|
2301
|
-
originalCellCount,
|
|
2302
|
-
);
|
|
2303
|
-
expect(state.cellData[nextCellId].code).toBe("line1\nline2");
|
|
870
|
+
it("can clear logs", () => {
|
|
871
|
+
state.cellLogs = [
|
|
872
|
+
{
|
|
873
|
+
level: "stderr",
|
|
874
|
+
message: "log1",
|
|
875
|
+
timestamp: 0,
|
|
876
|
+
source: { type: "cell", cellId: firstCellId },
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
level: "stderr",
|
|
880
|
+
message: "log1",
|
|
881
|
+
timestamp: 0,
|
|
882
|
+
source: { type: "cell", cellId: firstCellId },
|
|
883
|
+
},
|
|
884
|
+
];
|
|
885
|
+
actions.clearLogs();
|
|
886
|
+
expect(state.cellLogs).toEqual([]);
|
|
2304
887
|
});
|
|
2305
888
|
|
|
2306
889
|
it("can handle multiple console outputs", () => {
|
|
@@ -2322,7 +905,6 @@ describe("cell reducer", () => {
|
|
|
2322
905
|
output: undefined,
|
|
2323
906
|
console: [STDOUT1, STDOUT2],
|
|
2324
907
|
status: "running",
|
|
2325
|
-
stale_inputs: null,
|
|
2326
908
|
timestamp: new Date(20).getTime() as Seconds,
|
|
2327
909
|
});
|
|
2328
910
|
|
|
@@ -2339,407 +921,6 @@ describe("cell reducer", () => {
|
|
|
2339
921
|
`);
|
|
2340
922
|
});
|
|
2341
923
|
|
|
2342
|
-
it("can add a column breakpoint", () => {
|
|
2343
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2344
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2345
|
-
actions.createNewCell({ cellId: cellId("2"), before: false });
|
|
2346
|
-
|
|
2347
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2348
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2349
|
-
"
|
|
2350
|
-
[0] ''
|
|
2351
|
-
|
|
2352
|
-
[1] ''
|
|
2353
|
-
|
|
2354
|
-
[2] ''
|
|
2355
|
-
|
|
2356
|
-
[3] ''
|
|
2357
|
-
"
|
|
2358
|
-
`);
|
|
2359
|
-
|
|
2360
|
-
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2361
|
-
|
|
2362
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2363
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2364
|
-
"
|
|
2365
|
-
> col 0
|
|
2366
|
-
[0] ''
|
|
2367
|
-
|
|
2368
|
-
[1] ''
|
|
2369
|
-
|
|
2370
|
-
> col 1
|
|
2371
|
-
[2] ''
|
|
2372
|
-
|
|
2373
|
-
[3] ''
|
|
2374
|
-
"
|
|
2375
|
-
`);
|
|
2376
|
-
|
|
2377
|
-
// Check that the cells are in the correct columns
|
|
2378
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2379
|
-
cellId("0"),
|
|
2380
|
-
cellId("1"),
|
|
2381
|
-
]);
|
|
2382
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([
|
|
2383
|
-
cellId("2"),
|
|
2384
|
-
cellId("3"),
|
|
2385
|
-
]);
|
|
2386
|
-
});
|
|
2387
|
-
|
|
2388
|
-
it("cannot add a column breakpoint before the first cell", () => {
|
|
2389
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2390
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2391
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2392
|
-
actions.addColumnBreakpoint({ cellId: firstCellId });
|
|
2393
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2394
|
-
});
|
|
2395
|
-
|
|
2396
|
-
it("can delete a column", () => {
|
|
2397
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2398
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2399
|
-
actions.createNewCell({ cellId: cellId("2"), before: false });
|
|
2400
|
-
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2401
|
-
|
|
2402
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2403
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2404
|
-
"
|
|
2405
|
-
> col 0
|
|
2406
|
-
[0] ''
|
|
2407
|
-
|
|
2408
|
-
[1] ''
|
|
2409
|
-
|
|
2410
|
-
> col 1
|
|
2411
|
-
[2] ''
|
|
2412
|
-
|
|
2413
|
-
[3] ''
|
|
2414
|
-
"
|
|
2415
|
-
`);
|
|
2416
|
-
|
|
2417
|
-
const columnId = state.cellIds.atOrThrow(0).id;
|
|
2418
|
-
actions.deleteColumn({ columnId: columnId });
|
|
2419
|
-
|
|
2420
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2421
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2422
|
-
"
|
|
2423
|
-
[2] ''
|
|
2424
|
-
|
|
2425
|
-
[3] ''
|
|
2426
|
-
|
|
2427
|
-
[0] ''
|
|
2428
|
-
|
|
2429
|
-
[1] ''
|
|
2430
|
-
"
|
|
2431
|
-
`);
|
|
2432
|
-
|
|
2433
|
-
// Check that all cells are now in the remaining column
|
|
2434
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2435
|
-
"2",
|
|
2436
|
-
"3",
|
|
2437
|
-
"0",
|
|
2438
|
-
"1",
|
|
2439
|
-
]);
|
|
2440
|
-
});
|
|
2441
|
-
|
|
2442
|
-
it("deleting the last column does nothing", () => {
|
|
2443
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2444
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2445
|
-
|
|
2446
|
-
const initialState = { ...state };
|
|
2447
|
-
|
|
2448
|
-
actions.deleteColumn({ columnId: initialState.cellIds.atOrThrow(0).id });
|
|
2449
|
-
|
|
2450
|
-
// State should not change
|
|
2451
|
-
expect(state).toEqual(initialState);
|
|
2452
|
-
});
|
|
2453
|
-
|
|
2454
|
-
it("can drop a cell over another cell", () => {
|
|
2455
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2456
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2457
|
-
actions.createNewCell({ cellId: cellId("2"), before: false });
|
|
2458
|
-
|
|
2459
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2460
|
-
"
|
|
2461
|
-
[0] ''
|
|
2462
|
-
|
|
2463
|
-
[1] ''
|
|
2464
|
-
|
|
2465
|
-
[2] ''
|
|
2466
|
-
|
|
2467
|
-
[3] ''
|
|
2468
|
-
"
|
|
2469
|
-
`);
|
|
2470
|
-
|
|
2471
|
-
actions.dropCellOverCell({
|
|
2472
|
-
cellId: cellId("0"),
|
|
2473
|
-
overCellId: cellId("3"),
|
|
2474
|
-
});
|
|
2475
|
-
|
|
2476
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2477
|
-
"
|
|
2478
|
-
[1] ''
|
|
2479
|
-
|
|
2480
|
-
[2] ''
|
|
2481
|
-
|
|
2482
|
-
[3] ''
|
|
2483
|
-
|
|
2484
|
-
[0] ''
|
|
2485
|
-
"
|
|
2486
|
-
`);
|
|
2487
|
-
});
|
|
2488
|
-
|
|
2489
|
-
it("can drop a cell over a new column", () => {
|
|
2490
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2491
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2492
|
-
|
|
2493
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2494
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2495
|
-
"
|
|
2496
|
-
[0] ''
|
|
2497
|
-
|
|
2498
|
-
[1] ''
|
|
2499
|
-
|
|
2500
|
-
[2] ''
|
|
2501
|
-
"
|
|
2502
|
-
`);
|
|
2503
|
-
|
|
2504
|
-
actions.dropOverNewColumn({ cellId: cellId("1") });
|
|
2505
|
-
|
|
2506
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2507
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2508
|
-
"
|
|
2509
|
-
> col 0
|
|
2510
|
-
[0] ''
|
|
2511
|
-
|
|
2512
|
-
[2] ''
|
|
2513
|
-
|
|
2514
|
-
> col 1
|
|
2515
|
-
[1] ''
|
|
2516
|
-
"
|
|
2517
|
-
`);
|
|
2518
|
-
|
|
2519
|
-
// Check that the cells are in the correct columns
|
|
2520
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2521
|
-
cellId("0"),
|
|
2522
|
-
cellId("2"),
|
|
2523
|
-
]);
|
|
2524
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([cellId("1")]);
|
|
2525
|
-
});
|
|
2526
|
-
|
|
2527
|
-
it("can drop a column over another column", () => {
|
|
2528
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2529
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2530
|
-
actions.createNewCell({ cellId: cellId("2"), before: false });
|
|
2531
|
-
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2532
|
-
|
|
2533
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2534
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2535
|
-
"
|
|
2536
|
-
> col 0
|
|
2537
|
-
[0] ''
|
|
2538
|
-
|
|
2539
|
-
[1] ''
|
|
2540
|
-
|
|
2541
|
-
> col 1
|
|
2542
|
-
[2] ''
|
|
2543
|
-
|
|
2544
|
-
[3] ''
|
|
2545
|
-
"
|
|
2546
|
-
`);
|
|
2547
|
-
|
|
2548
|
-
const columnId0 = state.cellIds.atOrThrow(0).id;
|
|
2549
|
-
const columnId1 = state.cellIds.atOrThrow(1).id;
|
|
2550
|
-
expect(columnId0).not.toBe(columnId1);
|
|
2551
|
-
actions.moveColumn({ column: columnId1, overColumn: columnId0 });
|
|
2552
|
-
|
|
2553
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2554
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2555
|
-
"
|
|
2556
|
-
> col 0
|
|
2557
|
-
[2] ''
|
|
2558
|
-
|
|
2559
|
-
[3] ''
|
|
2560
|
-
|
|
2561
|
-
> col 1
|
|
2562
|
-
[0] ''
|
|
2563
|
-
|
|
2564
|
-
[1] ''
|
|
2565
|
-
"
|
|
2566
|
-
`);
|
|
2567
|
-
|
|
2568
|
-
// Check that the columns have swapped positions
|
|
2569
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2570
|
-
cellId("2"),
|
|
2571
|
-
cellId("3"),
|
|
2572
|
-
]);
|
|
2573
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([
|
|
2574
|
-
cellId("0"),
|
|
2575
|
-
cellId("1"),
|
|
2576
|
-
]);
|
|
2577
|
-
});
|
|
2578
|
-
|
|
2579
|
-
it("can compact columns", () => {
|
|
2580
|
-
// Create initial state with 3 columns, including an empty one
|
|
2581
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2582
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2583
|
-
actions.addColumnBreakpoint({ cellId: cellId("1") });
|
|
2584
|
-
actions.addColumnBreakpoint({ cellId: cellId("2") });
|
|
2585
|
-
actions.dropOverNewColumn({ cellId: cellId("2") });
|
|
2586
|
-
|
|
2587
|
-
expect(state.cellIds.getColumns().length).toBe(4);
|
|
2588
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2589
|
-
"
|
|
2590
|
-
> col 0
|
|
2591
|
-
[0] ''
|
|
2592
|
-
|
|
2593
|
-
> col 1
|
|
2594
|
-
[1] ''
|
|
2595
|
-
|
|
2596
|
-
> col 2
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
> col 3
|
|
2600
|
-
[2] ''
|
|
2601
|
-
"
|
|
2602
|
-
`);
|
|
2603
|
-
|
|
2604
|
-
// Check initial column structure
|
|
2605
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([cellId("0")]);
|
|
2606
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([cellId("1")]);
|
|
2607
|
-
expect(state.cellIds.getColumns()[2].topLevelIds).toEqual([]);
|
|
2608
|
-
expect(state.cellIds.getColumns()[3].topLevelIds).toEqual([cellId("2")]);
|
|
2609
|
-
|
|
2610
|
-
// Compact columns
|
|
2611
|
-
actions.compactColumns();
|
|
2612
|
-
|
|
2613
|
-
expect(state.cellIds.getColumns().length).toBe(3);
|
|
2614
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2615
|
-
"
|
|
2616
|
-
> col 0
|
|
2617
|
-
[0] ''
|
|
2618
|
-
|
|
2619
|
-
> col 1
|
|
2620
|
-
[1] ''
|
|
2621
|
-
|
|
2622
|
-
> col 2
|
|
2623
|
-
[2] ''
|
|
2624
|
-
"
|
|
2625
|
-
`);
|
|
2626
|
-
|
|
2627
|
-
// Check compacted column structure
|
|
2628
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([cellId("0")]);
|
|
2629
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([cellId("1")]);
|
|
2630
|
-
expect(state.cellIds.getColumns()[2].topLevelIds).toEqual([cellId("2")]);
|
|
2631
|
-
});
|
|
2632
|
-
|
|
2633
|
-
it("rebuildCellColumns regroups cells by config.column", () => {
|
|
2634
|
-
// Create four cells in a single column.
|
|
2635
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2636
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2637
|
-
actions.createNewCell({ cellId: cellId("2"), before: false });
|
|
2638
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2639
|
-
|
|
2640
|
-
// Explicitly set config.column on each cell. This ONLY updates metadata —
|
|
2641
|
-
// updateCellConfig does not touch the MultiColumn tree.
|
|
2642
|
-
actions.updateCellConfig({
|
|
2643
|
-
cellId: cellId("0"),
|
|
2644
|
-
config: { column: 0 },
|
|
2645
|
-
});
|
|
2646
|
-
actions.updateCellConfig({
|
|
2647
|
-
cellId: cellId("2"),
|
|
2648
|
-
config: { column: 1 },
|
|
2649
|
-
});
|
|
2650
|
-
|
|
2651
|
-
// Tree is still a single column at this point.
|
|
2652
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2653
|
-
|
|
2654
|
-
// Now rebuild the column tree from metadata.
|
|
2655
|
-
actions.rebuildCellColumns({
|
|
2656
|
-
cellIds: [cellId("0"), cellId("1"), cellId("2"), cellId("3")],
|
|
2657
|
-
});
|
|
2658
|
-
|
|
2659
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2660
|
-
// Cell 1 inherits from 0 (col 0), cell 3 inherits from 2 (col 1).
|
|
2661
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2662
|
-
cellId("0"),
|
|
2663
|
-
cellId("1"),
|
|
2664
|
-
]);
|
|
2665
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([
|
|
2666
|
-
cellId("2"),
|
|
2667
|
-
cellId("3"),
|
|
2668
|
-
]);
|
|
2669
|
-
});
|
|
2670
|
-
|
|
2671
|
-
it("rebuildCellColumns with explicit column on every cell", () => {
|
|
2672
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2673
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2674
|
-
actions.createNewCell({ cellId: cellId("2"), before: false });
|
|
2675
|
-
|
|
2676
|
-
for (const [id, col] of [
|
|
2677
|
-
["0", 1],
|
|
2678
|
-
["1", 0],
|
|
2679
|
-
["2", 1],
|
|
2680
|
-
["3", 0],
|
|
2681
|
-
] as const) {
|
|
2682
|
-
actions.updateCellConfig({ cellId: cellId(id), config: { column: col } });
|
|
2683
|
-
}
|
|
2684
|
-
|
|
2685
|
-
actions.rebuildCellColumns({
|
|
2686
|
-
cellIds: [cellId("0"), cellId("1"), cellId("2"), cellId("3")],
|
|
2687
|
-
});
|
|
2688
|
-
|
|
2689
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2690
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2691
|
-
cellId("1"),
|
|
2692
|
-
cellId("3"),
|
|
2693
|
-
]);
|
|
2694
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([
|
|
2695
|
-
cellId("0"),
|
|
2696
|
-
cellId("2"),
|
|
2697
|
-
]);
|
|
2698
|
-
});
|
|
2699
|
-
|
|
2700
|
-
it("rebuildCellColumns collapses to one column when all cells are col 0", () => {
|
|
2701
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2702
|
-
actions.addColumnBreakpoint({ cellId: cellId("1") });
|
|
2703
|
-
expect(state.cellIds.getColumns().length).toBe(2);
|
|
2704
|
-
|
|
2705
|
-
// Wipe column metadata back to 0 for both cells.
|
|
2706
|
-
actions.updateCellConfig({ cellId: cellId("0"), config: { column: 0 } });
|
|
2707
|
-
actions.updateCellConfig({ cellId: cellId("1"), config: { column: 0 } });
|
|
2708
|
-
|
|
2709
|
-
actions.rebuildCellColumns({
|
|
2710
|
-
cellIds: [cellId("0"), cellId("1")],
|
|
2711
|
-
});
|
|
2712
|
-
|
|
2713
|
-
expect(state.cellIds.getColumns().length).toBe(1);
|
|
2714
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([
|
|
2715
|
-
cellId("0"),
|
|
2716
|
-
cellId("1"),
|
|
2717
|
-
]);
|
|
2718
|
-
});
|
|
2719
|
-
|
|
2720
|
-
it("rebuildCellColumns follows the provided order, not current tree order", () => {
|
|
2721
|
-
// Start with a single column.
|
|
2722
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
2723
|
-
actions.createNewCell({ cellId: cellId("1"), before: false });
|
|
2724
|
-
actions.updateCellConfig({ cellId: cellId("0"), config: { column: 0 } });
|
|
2725
|
-
actions.updateCellConfig({ cellId: cellId("2"), config: { column: 1 } });
|
|
2726
|
-
|
|
2727
|
-
// Pass the reversed order. The rebuild should honor it.
|
|
2728
|
-
actions.rebuildCellColumns({
|
|
2729
|
-
cellIds: [cellId("2"), cellId("1"), cellId("0")],
|
|
2730
|
-
});
|
|
2731
|
-
|
|
2732
|
-
// cellIds iteration:
|
|
2733
|
-
// 2 → col=1, pushed to col1, prev=1
|
|
2734
|
-
// 1 → col=null, pushed to col[prev=1] = col1
|
|
2735
|
-
// 0 → col=0, pushed to col0
|
|
2736
|
-
expect(state.cellIds.getColumns()[0].topLevelIds).toEqual([cellId("0")]);
|
|
2737
|
-
expect(state.cellIds.getColumns()[1].topLevelIds).toEqual([
|
|
2738
|
-
cellId("2"),
|
|
2739
|
-
cellId("1"),
|
|
2740
|
-
]);
|
|
2741
|
-
});
|
|
2742
|
-
|
|
2743
924
|
it("can clear output of a single cell", () => {
|
|
2744
925
|
// Set up initial state with output
|
|
2745
926
|
actions.handleCellMessage({
|
|
@@ -2757,7 +938,6 @@ describe("cell reducer", () => {
|
|
|
2757
938
|
timestamp: 0,
|
|
2758
939
|
},
|
|
2759
940
|
status: "idle",
|
|
2760
|
-
stale_inputs: null,
|
|
2761
941
|
timestamp: new Date(33).getTime() as Seconds,
|
|
2762
942
|
});
|
|
2763
943
|
|
|
@@ -2792,7 +972,6 @@ describe("cell reducer", () => {
|
|
|
2792
972
|
timestamp: 0,
|
|
2793
973
|
},
|
|
2794
974
|
status: "idle",
|
|
2795
|
-
stale_inputs: null,
|
|
2796
975
|
timestamp: new Date(33).getTime() as Seconds,
|
|
2797
976
|
});
|
|
2798
977
|
|
|
@@ -2806,7 +985,6 @@ describe("cell reducer", () => {
|
|
|
2806
985
|
timestamp: 0,
|
|
2807
986
|
},
|
|
2808
987
|
status: "idle",
|
|
2809
|
-
stale_inputs: null,
|
|
2810
988
|
timestamp: new Date(34).getTime() as Seconds,
|
|
2811
989
|
});
|
|
2812
990
|
|
|
@@ -2828,8 +1006,8 @@ describe("cell reducer", () => {
|
|
|
2828
1006
|
|
|
2829
1007
|
it("can clear output of all cells", () => {
|
|
2830
1008
|
// Create multiple cells with output
|
|
2831
|
-
|
|
2832
|
-
const secondCellId = state.cellIds
|
|
1009
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1010
|
+
const secondCellId = state.cellIds[1];
|
|
2833
1011
|
|
|
2834
1012
|
// Add output to both cells
|
|
2835
1013
|
const outputMessage = {
|
|
@@ -2846,7 +1024,6 @@ describe("cell reducer", () => {
|
|
|
2846
1024
|
timestamp: 0,
|
|
2847
1025
|
},
|
|
2848
1026
|
status: "idle",
|
|
2849
|
-
stale_inputs: null,
|
|
2850
1027
|
timestamp: new Date(33).getTime() as Seconds,
|
|
2851
1028
|
} as const;
|
|
2852
1029
|
|
|
@@ -2857,139 +1034,27 @@ describe("cell reducer", () => {
|
|
|
2857
1034
|
actions.handleCellMessage({
|
|
2858
1035
|
...outputMessage,
|
|
2859
1036
|
cell_id: secondCellId,
|
|
2860
|
-
});
|
|
2861
|
-
|
|
2862
|
-
// Verify initial state has output
|
|
2863
|
-
expect(state.cellRuntime[firstCellId].output).not.toBeNull();
|
|
2864
|
-
expect(state.cellRuntime[firstCellId].consoleOutputs.length).toBe(1);
|
|
2865
|
-
expect(state.cellRuntime[secondCellId].output).not.toBeNull();
|
|
2866
|
-
expect(state.cellRuntime[secondCellId].consoleOutputs.length).toBe(1);
|
|
2867
|
-
|
|
2868
|
-
// Clear all outputs
|
|
2869
|
-
actions.clearAllCellOutputs();
|
|
2870
|
-
|
|
2871
|
-
// Verify all outputs are cleared
|
|
2872
|
-
expect(state.cellRuntime[firstCellId].output).toBeNull();
|
|
2873
|
-
expect(state.cellRuntime[firstCellId].consoleOutputs).toEqual([]);
|
|
2874
|
-
expect(state.cellRuntime[secondCellId].output).toBeNull();
|
|
2875
|
-
expect(state.cellRuntime[secondCellId].consoleOutputs).toEqual([]);
|
|
2876
|
-
});
|
|
2877
|
-
|
|
2878
|
-
it("skips creating new cell if code exists and skipIfCodeExists is true", () => {
|
|
2879
|
-
// Add initial cell with code
|
|
2880
|
-
actions.updateCellCode({
|
|
2881
|
-
cellId: firstCellId,
|
|
2882
|
-
code: "import numpy as np",
|
|
2883
|
-
formattingChange: false,
|
|
2884
|
-
});
|
|
2885
|
-
|
|
2886
|
-
// Try to create new cell with same code and skipIfCodeExists
|
|
2887
|
-
actions.createNewCell({
|
|
2888
|
-
cellId: "__end__",
|
|
2889
|
-
code: "import numpy as np",
|
|
2890
|
-
before: false,
|
|
2891
|
-
skipIfCodeExists: true,
|
|
2892
|
-
});
|
|
2893
|
-
|
|
2894
|
-
// Should still only have one cell
|
|
2895
|
-
expect(state.cellIds.inOrderIds.length).toBe(1);
|
|
2896
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2897
|
-
"
|
|
2898
|
-
[0] 'import numpy as np'
|
|
2899
|
-
"
|
|
2900
|
-
`);
|
|
2901
|
-
|
|
2902
|
-
// Verify we can still add cell with different code
|
|
2903
|
-
actions.createNewCell({
|
|
2904
|
-
cellId: "__end__",
|
|
2905
|
-
code: "import pandas as pd",
|
|
2906
|
-
before: false,
|
|
2907
|
-
skipIfCodeExists: true,
|
|
2908
|
-
});
|
|
2909
|
-
|
|
2910
|
-
expect(state.cellIds.inOrderIds.length).toBe(2);
|
|
2911
|
-
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
2912
|
-
"
|
|
2913
|
-
[0] 'import numpy as np'
|
|
2914
|
-
|
|
2915
|
-
[1] 'import pandas as pd'
|
|
2916
|
-
"
|
|
2917
|
-
`);
|
|
2918
|
-
});
|
|
2919
|
-
|
|
2920
|
-
it("can create and noop-update a setup cell", () => {
|
|
2921
|
-
// Create the setup cell
|
|
2922
|
-
actions.addSetupCellIfDoesntExist({ code: "# Setup code" });
|
|
2923
|
-
|
|
2924
|
-
// Check that setup cell was created
|
|
2925
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2926
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2927
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2928
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2929
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2930
|
-
|
|
2931
|
-
// Update the setup cell
|
|
2932
|
-
actions.addSetupCellIfDoesntExist({ code: "# Updated setup code" });
|
|
2933
|
-
|
|
2934
|
-
// Check that the setup cell did not change, since it already exists
|
|
2935
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2936
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2937
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2938
|
-
});
|
|
2939
|
-
|
|
2940
|
-
it("can delete and undelete the setup cell", () => {
|
|
2941
|
-
// Create the setup cell
|
|
2942
|
-
actions.addSetupCellIfDoesntExist({ code: "# Setup code" });
|
|
2943
|
-
|
|
2944
|
-
// Check that setup cell was created
|
|
2945
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2946
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2947
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2948
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2949
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2950
|
-
|
|
2951
|
-
// Delete the setup cell
|
|
2952
|
-
actions.deleteCell({ cellId: SETUP_CELL_ID });
|
|
2953
|
-
|
|
2954
|
-
// Check that setup cell was deleted
|
|
2955
|
-
expect(state.cellData[SETUP_CELL_ID]).toBeDefined(); // we keep old state
|
|
2956
|
-
expect(state.cellIds.inOrderIds).not.toContain(SETUP_CELL_ID);
|
|
2957
|
-
|
|
2958
|
-
// Undo delete the setup cell
|
|
2959
|
-
actions.undoDeleteCell();
|
|
2960
|
-
|
|
2961
|
-
// Check that setup cell was restored
|
|
2962
|
-
expect(state.cellData[SETUP_CELL_ID].id).toBe(SETUP_CELL_ID);
|
|
2963
|
-
expect(state.cellData[SETUP_CELL_ID].name).toBe("setup");
|
|
2964
|
-
expect(state.cellData[SETUP_CELL_ID].code).toBe("# Setup code");
|
|
2965
|
-
expect(state.cellData[SETUP_CELL_ID].edited).toBe(true);
|
|
2966
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
2967
|
-
|
|
2968
|
-
// Verify scrollKey is set to the restored setup cell
|
|
2969
|
-
expect(state.scrollKey).toBe(SETUP_CELL_ID);
|
|
2970
|
-
});
|
|
2971
|
-
|
|
2972
|
-
it("can delete and then create a new setup cell", () => {
|
|
2973
|
-
// Create the setup cell
|
|
2974
|
-
actions.addSetupCellIfDoesntExist({ code: "# Setup code" });
|
|
1037
|
+
});
|
|
2975
1038
|
|
|
2976
|
-
//
|
|
2977
|
-
|
|
1039
|
+
// Verify initial state has output
|
|
1040
|
+
expect(state.cellRuntime[firstCellId].output).not.toBeNull();
|
|
1041
|
+
expect(state.cellRuntime[firstCellId].consoleOutputs.length).toBe(1);
|
|
1042
|
+
expect(state.cellRuntime[secondCellId].output).not.toBeNull();
|
|
1043
|
+
expect(state.cellRuntime[secondCellId].consoleOutputs.length).toBe(1);
|
|
2978
1044
|
|
|
2979
|
-
//
|
|
2980
|
-
actions.
|
|
1045
|
+
// Clear all outputs
|
|
1046
|
+
actions.clearAllCellOutputs();
|
|
2981
1047
|
|
|
2982
|
-
//
|
|
2983
|
-
expect(state.
|
|
2984
|
-
expect(state.
|
|
2985
|
-
expect(state.
|
|
2986
|
-
expect(state.
|
|
2987
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
1048
|
+
// Verify all outputs are cleared
|
|
1049
|
+
expect(state.cellRuntime[firstCellId].output).toBeNull();
|
|
1050
|
+
expect(state.cellRuntime[firstCellId].consoleOutputs).toEqual([]);
|
|
1051
|
+
expect(state.cellRuntime[secondCellId].output).toBeNull();
|
|
1052
|
+
expect(state.cellRuntime[secondCellId].consoleOutputs).toEqual([]);
|
|
2988
1053
|
});
|
|
2989
1054
|
|
|
2990
1055
|
it("can clear all outputs", () => {
|
|
2991
1056
|
// Add a cell and give it output
|
|
2992
|
-
|
|
1057
|
+
seedCell({
|
|
2993
1058
|
cellId: firstCellId,
|
|
2994
1059
|
before: false,
|
|
2995
1060
|
});
|
|
@@ -3017,522 +1082,13 @@ describe("cell reducer", () => {
|
|
|
3017
1082
|
expect(state.cellRuntime[cell2Id].output).toBeNull();
|
|
3018
1083
|
});
|
|
3019
1084
|
|
|
3020
|
-
describe("moveToNextCell", () => {
|
|
3021
|
-
let cell1Id: CellId;
|
|
3022
|
-
let cell2Id: CellId;
|
|
3023
|
-
let cell3Id: CellId;
|
|
3024
|
-
|
|
3025
|
-
beforeEach(() => {
|
|
3026
|
-
// Create a few cells to work with
|
|
3027
|
-
actions.createNewCell({ cellId: "__end__", before: false });
|
|
3028
|
-
actions.createNewCell({ cellId: "__end__", before: false });
|
|
3029
|
-
|
|
3030
|
-
cell1Id = state.cellIds.inOrderIds[0];
|
|
3031
|
-
cell2Id = state.cellIds.inOrderIds[1];
|
|
3032
|
-
cell3Id = state.cellIds.inOrderIds[2];
|
|
3033
|
-
});
|
|
3034
|
-
|
|
3035
|
-
it("creates new cell when moving after last cell with noCreate=false", () => {
|
|
3036
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
3037
|
-
|
|
3038
|
-
actions.moveToNextCell({
|
|
3039
|
-
cellId: cell3Id,
|
|
3040
|
-
before: false,
|
|
3041
|
-
noCreate: false,
|
|
3042
|
-
});
|
|
3043
|
-
|
|
3044
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount + 1);
|
|
3045
|
-
});
|
|
3046
|
-
|
|
3047
|
-
it("creates new cell when moving before first cell with noCreate=false", () => {
|
|
3048
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
3049
|
-
|
|
3050
|
-
actions.moveToNextCell({
|
|
3051
|
-
cellId: cell1Id,
|
|
3052
|
-
before: true,
|
|
3053
|
-
noCreate: false,
|
|
3054
|
-
});
|
|
3055
|
-
|
|
3056
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount + 1);
|
|
3057
|
-
});
|
|
3058
|
-
|
|
3059
|
-
it("does not create new cell when moving after last cell with noCreate=true", () => {
|
|
3060
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
3061
|
-
const initialState = { ...state };
|
|
3062
|
-
|
|
3063
|
-
actions.moveToNextCell({
|
|
3064
|
-
cellId: cell3Id,
|
|
3065
|
-
before: false,
|
|
3066
|
-
noCreate: true,
|
|
3067
|
-
});
|
|
3068
|
-
|
|
3069
|
-
// Should not create a new cell
|
|
3070
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount);
|
|
3071
|
-
// Should not crash or throw an error
|
|
3072
|
-
expect(state.cellIds.inOrderIds).toEqual(initialState.cellIds.inOrderIds);
|
|
3073
|
-
});
|
|
3074
|
-
|
|
3075
|
-
it("does not create new cell when moving before first cell with noCreate=true", () => {
|
|
3076
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
3077
|
-
const initialState = { ...state };
|
|
3078
|
-
|
|
3079
|
-
actions.moveToNextCell({ cellId: cell1Id, before: true, noCreate: true });
|
|
3080
|
-
|
|
3081
|
-
// Should not create a new cell
|
|
3082
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount);
|
|
3083
|
-
// Should not crash or throw an error
|
|
3084
|
-
expect(state.cellIds.inOrderIds).toEqual(initialState.cellIds.inOrderIds);
|
|
3085
|
-
});
|
|
3086
|
-
|
|
3087
|
-
it("focuses next cell when moving within bounds", () => {
|
|
3088
|
-
const focusSpy = vi.mocked(focusAndScrollCellIntoView);
|
|
3089
|
-
focusSpy.mockClear();
|
|
3090
|
-
|
|
3091
|
-
actions.moveToNextCell({
|
|
3092
|
-
cellId: cell1Id,
|
|
3093
|
-
before: false,
|
|
3094
|
-
noCreate: true,
|
|
3095
|
-
});
|
|
3096
|
-
|
|
3097
|
-
expect(focusSpy).toHaveBeenCalledWith({
|
|
3098
|
-
cellId: cell2Id,
|
|
3099
|
-
cell: state.cellHandles[cell2Id],
|
|
3100
|
-
isCodeHidden: false,
|
|
3101
|
-
codeFocus: "top",
|
|
3102
|
-
variableName: undefined,
|
|
3103
|
-
});
|
|
3104
|
-
});
|
|
3105
|
-
|
|
3106
|
-
it("focuses previous cell when moving backward within bounds", () => {
|
|
3107
|
-
const focusSpy = vi.mocked(focusAndScrollCellIntoView);
|
|
3108
|
-
focusSpy.mockClear();
|
|
3109
|
-
|
|
3110
|
-
actions.moveToNextCell({ cellId: cell2Id, before: true, noCreate: true });
|
|
3111
|
-
|
|
3112
|
-
expect(focusSpy).toHaveBeenCalledWith({
|
|
3113
|
-
cellId: cell1Id,
|
|
3114
|
-
cell: state.cellHandles[cell1Id],
|
|
3115
|
-
isCodeHidden: false,
|
|
3116
|
-
codeFocus: "bottom",
|
|
3117
|
-
variableName: undefined,
|
|
3118
|
-
});
|
|
3119
|
-
});
|
|
3120
|
-
|
|
3121
|
-
it("does not move focus from scratch cell", () => {
|
|
3122
|
-
const focusSpy = vi.mocked(focusAndScrollCellIntoView);
|
|
3123
|
-
focusSpy.mockClear();
|
|
3124
|
-
const initialState = { ...state };
|
|
3125
|
-
|
|
3126
|
-
actions.moveToNextCell({
|
|
3127
|
-
cellId: SCRATCH_CELL_ID,
|
|
3128
|
-
before: false,
|
|
3129
|
-
noCreate: false,
|
|
3130
|
-
});
|
|
3131
|
-
|
|
3132
|
-
expect(focusSpy).not.toHaveBeenCalled();
|
|
3133
|
-
expect(state.cellIds.inOrderIds).toEqual(initialState.cellIds.inOrderIds);
|
|
3134
|
-
});
|
|
3135
|
-
});
|
|
3136
|
-
|
|
3137
|
-
describe("untouched cells functionality", () => {
|
|
3138
|
-
it("starts with empty untouchedNewCells set", () => {
|
|
3139
|
-
expect(state.untouchedNewCells).toEqual(new Set());
|
|
3140
|
-
});
|
|
3141
|
-
|
|
3142
|
-
it("can create a new cell with hideCode option", () => {
|
|
3143
|
-
const initialCellCount = state.cellIds.inOrderIds.length;
|
|
3144
|
-
|
|
3145
|
-
actions.createNewCell({
|
|
3146
|
-
cellId: "__end__",
|
|
3147
|
-
before: false,
|
|
3148
|
-
hideCode: true,
|
|
3149
|
-
});
|
|
3150
|
-
|
|
3151
|
-
expect(state.cellIds.inOrderIds.length).toBe(initialCellCount + 1);
|
|
3152
|
-
const newCellId =
|
|
3153
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3154
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3155
|
-
});
|
|
3156
|
-
|
|
3157
|
-
it("adds interactively-created hidden cell with boilerplate code to untouchedNewCells", () => {
|
|
3158
|
-
// Markdown cells are created with hideCode and non-empty default code
|
|
3159
|
-
// (e.g. `mo.md(r"""\n""")`). They are user-initiated, so their editor
|
|
3160
|
-
// should be shown until first blur.
|
|
3161
|
-
actions.createNewCell({
|
|
3162
|
-
cellId: "__end__",
|
|
3163
|
-
before: false,
|
|
3164
|
-
code: 'mo.md(r"""\n""")',
|
|
3165
|
-
hideCode: true,
|
|
3166
|
-
autoFocus: true,
|
|
3167
|
-
});
|
|
3168
|
-
|
|
3169
|
-
const newCellId =
|
|
3170
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3171
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3172
|
-
});
|
|
3173
|
-
|
|
3174
|
-
it("does not add programmatically-created hidden cell with code to untouchedNewCells", () => {
|
|
3175
|
-
// Cells created by the kernel (e.g. via code_mode) carry code and
|
|
3176
|
-
// autoFocus=false; their hide_code must take effect immediately.
|
|
3177
|
-
actions.createNewCell({
|
|
3178
|
-
cellId: "__end__",
|
|
3179
|
-
before: false,
|
|
3180
|
-
code: "x = 1",
|
|
3181
|
-
hideCode: true,
|
|
3182
|
-
autoFocus: false,
|
|
3183
|
-
});
|
|
3184
|
-
|
|
3185
|
-
const newCellId =
|
|
3186
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3187
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3188
|
-
});
|
|
3189
|
-
|
|
3190
|
-
it("does not add cell to untouchedNewCells when hideCode is false", () => {
|
|
3191
|
-
actions.createNewCell({
|
|
3192
|
-
cellId: "__end__",
|
|
3193
|
-
before: false,
|
|
3194
|
-
hideCode: false,
|
|
3195
|
-
});
|
|
3196
|
-
|
|
3197
|
-
const newCellId =
|
|
3198
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3199
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3200
|
-
});
|
|
3201
|
-
|
|
3202
|
-
it("does not add cell to untouchedNewCells when hideCode is undefined", () => {
|
|
3203
|
-
actions.createNewCell({
|
|
3204
|
-
cellId: "__end__",
|
|
3205
|
-
before: false,
|
|
3206
|
-
});
|
|
3207
|
-
|
|
3208
|
-
const newCellId =
|
|
3209
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3210
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3211
|
-
});
|
|
3212
|
-
|
|
3213
|
-
it("can mark a cell as touched", () => {
|
|
3214
|
-
// Create a cell with hideCode
|
|
3215
|
-
actions.createNewCell({
|
|
3216
|
-
cellId: "__end__",
|
|
3217
|
-
before: false,
|
|
3218
|
-
hideCode: true,
|
|
3219
|
-
});
|
|
3220
|
-
|
|
3221
|
-
const newCellId =
|
|
3222
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3223
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3224
|
-
|
|
3225
|
-
// Mark it as touched
|
|
3226
|
-
actions.markTouched({ cellId: newCellId });
|
|
3227
|
-
|
|
3228
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3229
|
-
});
|
|
3230
|
-
|
|
3231
|
-
it("markTouched is idempotent", () => {
|
|
3232
|
-
// Create a cell with hideCode
|
|
3233
|
-
actions.createNewCell({
|
|
3234
|
-
cellId: "__end__",
|
|
3235
|
-
before: false,
|
|
3236
|
-
hideCode: true,
|
|
3237
|
-
});
|
|
3238
|
-
|
|
3239
|
-
const newCellId =
|
|
3240
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3241
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3242
|
-
|
|
3243
|
-
// Mark it as touched multiple times
|
|
3244
|
-
actions.markTouched({ cellId: newCellId });
|
|
3245
|
-
actions.markTouched({ cellId: newCellId });
|
|
3246
|
-
actions.markTouched({ cellId: newCellId });
|
|
3247
|
-
|
|
3248
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3249
|
-
});
|
|
3250
|
-
|
|
3251
|
-
it("can mark a non-existent cell as touched without error", () => {
|
|
3252
|
-
const nonExistentCellId = cellId("non-existent");
|
|
3253
|
-
|
|
3254
|
-
expect(() => {
|
|
3255
|
-
actions.markTouched({ cellId: nonExistentCellId });
|
|
3256
|
-
}).not.toThrow();
|
|
3257
|
-
|
|
3258
|
-
expect(state.untouchedNewCells.has(nonExistentCellId)).toBe(false);
|
|
3259
|
-
});
|
|
3260
|
-
|
|
3261
|
-
it("can handle multiple untouched cells", () => {
|
|
3262
|
-
// Create multiple cells with hideCode
|
|
3263
|
-
actions.createNewCell({
|
|
3264
|
-
cellId: "__end__",
|
|
3265
|
-
before: false,
|
|
3266
|
-
hideCode: true,
|
|
3267
|
-
});
|
|
3268
|
-
actions.createNewCell({
|
|
3269
|
-
cellId: "__end__",
|
|
3270
|
-
before: false,
|
|
3271
|
-
hideCode: true,
|
|
3272
|
-
});
|
|
3273
|
-
actions.createNewCell({
|
|
3274
|
-
cellId: "__end__",
|
|
3275
|
-
before: false,
|
|
3276
|
-
hideCode: false,
|
|
3277
|
-
});
|
|
3278
|
-
|
|
3279
|
-
const cellIds = state.cellIds.inOrderIds;
|
|
3280
|
-
const cell1Id = cellIds[cellIds.length - 3];
|
|
3281
|
-
const cell2Id = cellIds[cellIds.length - 2];
|
|
3282
|
-
const cell3Id = cellIds[cellIds.length - 1];
|
|
3283
|
-
|
|
3284
|
-
expect(state.untouchedNewCells.has(cell1Id)).toBe(true);
|
|
3285
|
-
expect(state.untouchedNewCells.has(cell2Id)).toBe(true);
|
|
3286
|
-
expect(state.untouchedNewCells.has(cell3Id)).toBe(false);
|
|
3287
|
-
|
|
3288
|
-
// Mark one as touched
|
|
3289
|
-
actions.markTouched({ cellId: cell1Id });
|
|
3290
|
-
|
|
3291
|
-
expect(state.untouchedNewCells.has(cell1Id)).toBe(false);
|
|
3292
|
-
expect(state.untouchedNewCells.has(cell2Id)).toBe(true);
|
|
3293
|
-
expect(state.untouchedNewCells.has(cell3Id)).toBe(false);
|
|
3294
|
-
});
|
|
3295
|
-
|
|
3296
|
-
it("preserves untouched state when cells are moved", () => {
|
|
3297
|
-
// Create cells with hideCode
|
|
3298
|
-
actions.createNewCell({
|
|
3299
|
-
cellId: "__end__",
|
|
3300
|
-
before: false,
|
|
3301
|
-
hideCode: true,
|
|
3302
|
-
});
|
|
3303
|
-
actions.createNewCell({
|
|
3304
|
-
cellId: "__end__",
|
|
3305
|
-
before: false,
|
|
3306
|
-
hideCode: true,
|
|
3307
|
-
});
|
|
3308
|
-
|
|
3309
|
-
const cellIds = state.cellIds.inOrderIds;
|
|
3310
|
-
const cell1Id = cellIds[cellIds.length - 2];
|
|
3311
|
-
const cell2Id = cellIds[cellIds.length - 1];
|
|
3312
|
-
|
|
3313
|
-
expect(state.untouchedNewCells.has(cell1Id)).toBe(true);
|
|
3314
|
-
expect(state.untouchedNewCells.has(cell2Id)).toBe(true);
|
|
3315
|
-
|
|
3316
|
-
// Move cell1 to the end
|
|
3317
|
-
actions.moveCell({
|
|
3318
|
-
cellId: cell1Id,
|
|
3319
|
-
before: false,
|
|
3320
|
-
});
|
|
3321
|
-
|
|
3322
|
-
// Both cells should still be untouched
|
|
3323
|
-
expect(state.untouchedNewCells.has(cell1Id)).toBe(true);
|
|
3324
|
-
expect(state.untouchedNewCells.has(cell2Id)).toBe(true);
|
|
3325
|
-
});
|
|
3326
|
-
|
|
3327
|
-
it("does not remove untouched state when cell is deleted", () => {
|
|
3328
|
-
// We could implement this, but it doesn't actually affect downstream behavior.
|
|
3329
|
-
// It is easier to leave it, so `undo` works as expected.
|
|
3330
|
-
|
|
3331
|
-
// Create a cell with hideCode
|
|
3332
|
-
actions.createNewCell({
|
|
3333
|
-
cellId: "__end__",
|
|
3334
|
-
before: false,
|
|
3335
|
-
hideCode: true,
|
|
3336
|
-
});
|
|
3337
|
-
|
|
3338
|
-
const newCellId =
|
|
3339
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3340
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3341
|
-
|
|
3342
|
-
// Delete the cell
|
|
3343
|
-
actions.deleteCell({ cellId: newCellId });
|
|
3344
|
-
|
|
3345
|
-
// Does not actually remove untouched state
|
|
3346
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3347
|
-
});
|
|
3348
|
-
|
|
3349
|
-
it("restores untouched state when cell deletion is undone", () => {
|
|
3350
|
-
// Create a cell with hideCode
|
|
3351
|
-
actions.createNewCell({
|
|
3352
|
-
cellId: "__end__",
|
|
3353
|
-
before: false,
|
|
3354
|
-
hideCode: true,
|
|
3355
|
-
});
|
|
3356
|
-
|
|
3357
|
-
const newCellId =
|
|
3358
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3359
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3360
|
-
|
|
3361
|
-
// Delete the cell
|
|
3362
|
-
actions.deleteCell({ cellId: newCellId });
|
|
3363
|
-
// Still exists in untouchedNewCells
|
|
3364
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3365
|
-
|
|
3366
|
-
// Undo the deletion
|
|
3367
|
-
actions.undoDeleteCell();
|
|
3368
|
-
|
|
3369
|
-
// The cell should be restored but no longer untouched
|
|
3370
|
-
// (this is expected behavior - undoing doesn't restore untouched state)
|
|
3371
|
-
const restoredCellId =
|
|
3372
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3373
|
-
expect(state.untouchedNewCells.has(restoredCellId)).toBe(false);
|
|
3374
|
-
});
|
|
3375
|
-
|
|
3376
|
-
it("untouched cell behavior with hide_code config", () => {
|
|
3377
|
-
// Create a cell with hideCode and hide_code config
|
|
3378
|
-
actions.createNewCell({
|
|
3379
|
-
cellId: "__end__",
|
|
3380
|
-
before: false,
|
|
3381
|
-
hideCode: true,
|
|
3382
|
-
});
|
|
3383
|
-
|
|
3384
|
-
const newCellId =
|
|
3385
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3386
|
-
|
|
3387
|
-
// Update the cell config to hide code
|
|
3388
|
-
actions.updateCellConfig({
|
|
3389
|
-
cellId: newCellId,
|
|
3390
|
-
config: { hide_code: true },
|
|
3391
|
-
});
|
|
3392
|
-
|
|
3393
|
-
// Cell should be untouched and have hide_code config
|
|
3394
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3395
|
-
expect(state.cellData[newCellId].config.hide_code).toBe(true);
|
|
3396
|
-
|
|
3397
|
-
// Code should not be hidden because cell is untouched
|
|
3398
|
-
expect(exportedForTesting.isCellCodeHidden(state, newCellId)).toBe(false);
|
|
3399
|
-
|
|
3400
|
-
// Mark as touched
|
|
3401
|
-
actions.markTouched({ cellId: newCellId });
|
|
3402
|
-
|
|
3403
|
-
// Now code should be hidden
|
|
3404
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3405
|
-
expect(exportedForTesting.isCellCodeHidden(state, newCellId)).toBe(true);
|
|
3406
|
-
});
|
|
3407
|
-
|
|
3408
|
-
it("can mark an existing cell as untouched", () => {
|
|
3409
|
-
// Create a cell without hideCode (not in untouchedNewCells)
|
|
3410
|
-
actions.createNewCell({
|
|
3411
|
-
cellId: "__end__",
|
|
3412
|
-
before: false,
|
|
3413
|
-
hideCode: false,
|
|
3414
|
-
});
|
|
3415
|
-
|
|
3416
|
-
const newCellId =
|
|
3417
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3418
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3419
|
-
|
|
3420
|
-
// Mark it as untouched
|
|
3421
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3422
|
-
|
|
3423
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3424
|
-
});
|
|
3425
|
-
|
|
3426
|
-
it("markUntouched is idempotent", () => {
|
|
3427
|
-
// Create a cell without hideCode
|
|
3428
|
-
actions.createNewCell({
|
|
3429
|
-
cellId: "__end__",
|
|
3430
|
-
before: false,
|
|
3431
|
-
hideCode: false,
|
|
3432
|
-
});
|
|
3433
|
-
|
|
3434
|
-
const newCellId =
|
|
3435
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3436
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3437
|
-
|
|
3438
|
-
// Mark as untouched multiple times
|
|
3439
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3440
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3441
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3442
|
-
|
|
3443
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3444
|
-
});
|
|
3445
|
-
|
|
3446
|
-
it("markUntouched does not affect already untouched cells", () => {
|
|
3447
|
-
// Create a cell with hideCode (already in untouchedNewCells)
|
|
3448
|
-
actions.createNewCell({
|
|
3449
|
-
cellId: "__end__",
|
|
3450
|
-
before: false,
|
|
3451
|
-
hideCode: true,
|
|
3452
|
-
});
|
|
3453
|
-
|
|
3454
|
-
const newCellId =
|
|
3455
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3456
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3457
|
-
|
|
3458
|
-
// Calling markUntouched should not change anything
|
|
3459
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3460
|
-
|
|
3461
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3462
|
-
});
|
|
3463
|
-
|
|
3464
|
-
it("markTouched and markUntouched can toggle cell state", () => {
|
|
3465
|
-
// Create a cell without hideCode
|
|
3466
|
-
actions.createNewCell({
|
|
3467
|
-
cellId: "__end__",
|
|
3468
|
-
before: false,
|
|
3469
|
-
hideCode: false,
|
|
3470
|
-
});
|
|
3471
|
-
|
|
3472
|
-
const newCellId =
|
|
3473
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3474
|
-
|
|
3475
|
-
// Initially not untouched
|
|
3476
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3477
|
-
|
|
3478
|
-
// Mark as untouched
|
|
3479
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3480
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3481
|
-
|
|
3482
|
-
// Mark as touched
|
|
3483
|
-
actions.markTouched({ cellId: newCellId });
|
|
3484
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(false);
|
|
3485
|
-
|
|
3486
|
-
// Mark as untouched again
|
|
3487
|
-
actions.markUntouched({ cellId: newCellId });
|
|
3488
|
-
expect(state.untouchedNewCells.has(newCellId)).toBe(true);
|
|
3489
|
-
});
|
|
3490
|
-
|
|
3491
|
-
it("markUntouched works for markdown cell conversion scenario", () => {
|
|
3492
|
-
// Simulates converting a Python cell to Markdown
|
|
3493
|
-
// 1. Create a regular cell (no hideCode)
|
|
3494
|
-
actions.createNewCell({
|
|
3495
|
-
cellId: "__end__",
|
|
3496
|
-
before: false,
|
|
3497
|
-
hideCode: false,
|
|
3498
|
-
});
|
|
3499
|
-
|
|
3500
|
-
const cellId =
|
|
3501
|
-
state.cellIds.inOrderIds[state.cellIds.inOrderIds.length - 1];
|
|
3502
|
-
|
|
3503
|
-
// Cell starts without hide_code and not in untouchedNewCells
|
|
3504
|
-
expect(state.cellData[cellId].config.hide_code).toBe(false);
|
|
3505
|
-
expect(state.untouchedNewCells.has(cellId)).toBe(false);
|
|
3506
|
-
expect(exportedForTesting.isCellCodeHidden(state, cellId)).toBe(false);
|
|
3507
|
-
|
|
3508
|
-
// 2. Convert to markdown: set hide_code and mark as untouched
|
|
3509
|
-
actions.updateCellConfig({
|
|
3510
|
-
cellId,
|
|
3511
|
-
config: { hide_code: true },
|
|
3512
|
-
});
|
|
3513
|
-
actions.markUntouched({ cellId });
|
|
3514
|
-
|
|
3515
|
-
// Code should NOT be hidden because cell is untouched (user can edit)
|
|
3516
|
-
expect(state.cellData[cellId].config.hide_code).toBe(true);
|
|
3517
|
-
expect(state.untouchedNewCells.has(cellId)).toBe(true);
|
|
3518
|
-
expect(exportedForTesting.isCellCodeHidden(state, cellId)).toBe(false);
|
|
3519
|
-
|
|
3520
|
-
// 3. User blurs the cell (markTouched)
|
|
3521
|
-
actions.markTouched({ cellId });
|
|
3522
|
-
|
|
3523
|
-
// Now code should be hidden
|
|
3524
|
-
expect(state.untouchedNewCells.has(cellId)).toBe(false);
|
|
3525
|
-
expect(exportedForTesting.isCellCodeHidden(state, cellId)).toBe(true);
|
|
3526
|
-
});
|
|
3527
|
-
});
|
|
3528
|
-
|
|
3529
1085
|
describe("releaseCellAtoms", () => {
|
|
3530
1086
|
it("atom families cache atoms until explicitly removed", () => {
|
|
3531
1087
|
const { cellDataAtom, cellRuntimeAtom, cellHandleAtom } =
|
|
3532
1088
|
exportedForTesting;
|
|
3533
1089
|
|
|
3534
|
-
|
|
3535
|
-
const newCellId = state.cellIds
|
|
1090
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1091
|
+
const newCellId = state.cellIds[1];
|
|
3536
1092
|
|
|
3537
1093
|
const dataAtom1 = cellDataAtom(newCellId);
|
|
3538
1094
|
const runtimeAtom1 = cellRuntimeAtom(newCellId);
|
|
@@ -3547,116 +1103,6 @@ describe("cell reducer", () => {
|
|
|
3547
1103
|
expect(runtimeAtom2).toBe(runtimeAtom1);
|
|
3548
1104
|
expect(handleAtom2).toBe(handleAtom1);
|
|
3549
1105
|
});
|
|
3550
|
-
|
|
3551
|
-
it("cleans up atom family cache when cells are deleted", () => {
|
|
3552
|
-
const { cellDataAtom, cellRuntimeAtom, cellHandleAtom } =
|
|
3553
|
-
exportedForTesting;
|
|
3554
|
-
|
|
3555
|
-
actions.createNewCell({ cellId: firstCellId, before: false });
|
|
3556
|
-
const newCellId = state.cellIds.inOrderIds[1];
|
|
3557
|
-
|
|
3558
|
-
// Access to create cache entries
|
|
3559
|
-
const dataAtom1 = cellDataAtom(newCellId);
|
|
3560
|
-
const runtimeAtom1 = cellRuntimeAtom(newCellId);
|
|
3561
|
-
const handleAtom1 = cellHandleAtom(newCellId);
|
|
3562
|
-
|
|
3563
|
-
// Triggers purge
|
|
3564
|
-
actions.deleteCell({ cellId: newCellId });
|
|
3565
|
-
|
|
3566
|
-
// Access again (should be new instances after cleanup)
|
|
3567
|
-
const dataAtom2 = cellDataAtom(newCellId);
|
|
3568
|
-
const runtimeAtom2 = cellRuntimeAtom(newCellId);
|
|
3569
|
-
const handleAtom2 = cellHandleAtom(newCellId);
|
|
3570
|
-
|
|
3571
|
-
expect(dataAtom2).not.toBe(dataAtom1);
|
|
3572
|
-
expect(runtimeAtom2).not.toBe(runtimeAtom1);
|
|
3573
|
-
expect(handleAtom2).not.toBe(handleAtom1);
|
|
3574
|
-
});
|
|
3575
|
-
});
|
|
3576
|
-
});
|
|
3577
|
-
|
|
3578
|
-
describe("isCellCodeHidden", () => {
|
|
3579
|
-
const state = initialNotebookState();
|
|
3580
|
-
const firstCellId = state.cellIds.inOrderIds[0];
|
|
3581
|
-
|
|
3582
|
-
it("returns false when hide_code is false and cell is not untouched", () => {
|
|
3583
|
-
const testCellId = cellId("test-cell");
|
|
3584
|
-
const testState: NotebookState = {
|
|
3585
|
-
...state,
|
|
3586
|
-
cellData: {
|
|
3587
|
-
...state.cellData,
|
|
3588
|
-
[testCellId]: {
|
|
3589
|
-
...state.cellData[firstCellId],
|
|
3590
|
-
id: testCellId,
|
|
3591
|
-
config: { hide_code: false, disabled: false, column: null },
|
|
3592
|
-
},
|
|
3593
|
-
},
|
|
3594
|
-
untouchedNewCells: new Set(),
|
|
3595
|
-
};
|
|
3596
|
-
|
|
3597
|
-
expect(exportedForTesting.isCellCodeHidden(testState, testCellId)).toBe(
|
|
3598
|
-
false,
|
|
3599
|
-
);
|
|
3600
|
-
});
|
|
3601
|
-
|
|
3602
|
-
it("returns true when hide_code is true and cell is not untouched", () => {
|
|
3603
|
-
const testCellId = cellId("test-cell");
|
|
3604
|
-
const testState: NotebookState = {
|
|
3605
|
-
...state,
|
|
3606
|
-
cellData: {
|
|
3607
|
-
...state.cellData,
|
|
3608
|
-
[testCellId]: {
|
|
3609
|
-
...state.cellData[firstCellId],
|
|
3610
|
-
id: testCellId,
|
|
3611
|
-
config: { hide_code: true, disabled: false, column: null },
|
|
3612
|
-
},
|
|
3613
|
-
},
|
|
3614
|
-
untouchedNewCells: new Set(),
|
|
3615
|
-
};
|
|
3616
|
-
|
|
3617
|
-
expect(exportedForTesting.isCellCodeHidden(testState, testCellId)).toBe(
|
|
3618
|
-
true,
|
|
3619
|
-
);
|
|
3620
|
-
});
|
|
3621
|
-
|
|
3622
|
-
it("returns false when hide_code is true but cell is untouched", () => {
|
|
3623
|
-
const testCellId = cellId("test-cell");
|
|
3624
|
-
const testState: NotebookState = {
|
|
3625
|
-
...state,
|
|
3626
|
-
cellData: {
|
|
3627
|
-
...state.cellData,
|
|
3628
|
-
[testCellId]: {
|
|
3629
|
-
...state.cellData[firstCellId],
|
|
3630
|
-
id: testCellId,
|
|
3631
|
-
config: { hide_code: true, disabled: false, column: null },
|
|
3632
|
-
},
|
|
3633
|
-
},
|
|
3634
|
-
untouchedNewCells: new Set([testCellId]),
|
|
3635
|
-
};
|
|
3636
|
-
|
|
3637
|
-
expect(exportedForTesting.isCellCodeHidden(testState, testCellId)).toBe(
|
|
3638
|
-
false,
|
|
3639
|
-
);
|
|
3640
|
-
});
|
|
3641
|
-
|
|
3642
|
-
it("returns false when hide_code is false and cell is untouched", () => {
|
|
3643
|
-
const testCellId = cellId("test-cell");
|
|
3644
|
-
const testState: NotebookState = {
|
|
3645
|
-
...state,
|
|
3646
|
-
cellData: {
|
|
3647
|
-
...state.cellData,
|
|
3648
|
-
[testCellId]: {
|
|
3649
|
-
...state.cellData[firstCellId],
|
|
3650
|
-
id: testCellId,
|
|
3651
|
-
config: { hide_code: false, disabled: false, column: null },
|
|
3652
|
-
},
|
|
3653
|
-
},
|
|
3654
|
-
untouchedNewCells: new Set([testCellId]),
|
|
3655
|
-
};
|
|
3656
|
-
|
|
3657
|
-
expect(exportedForTesting.isCellCodeHidden(testState, testCellId)).toBe(
|
|
3658
|
-
false,
|
|
3659
|
-
);
|
|
3660
1106
|
});
|
|
3661
1107
|
});
|
|
3662
1108
|
|
|
@@ -3839,11 +1285,11 @@ describe("createTracebackInfoAtom", () => {
|
|
|
3839
1285
|
data: [{ type: "syntax", msg: "Syntax error", lineno: 1 }],
|
|
3840
1286
|
mimetype: "application/vnd.marimo+error",
|
|
3841
1287
|
},
|
|
3842
|
-
status: "queued",
|
|
3843
1288
|
},
|
|
3844
1289
|
},
|
|
3845
1290
|
}),
|
|
3846
1291
|
);
|
|
1292
|
+
MockExecutions.seed(store, [MockExecutions.queued(cellId("cell1"))]);
|
|
3847
1293
|
|
|
3848
1294
|
const tracebackAtom = exportedForTesting.createTracebackInfoAtom(
|
|
3849
1295
|
cellId("cell1"),
|
|
@@ -3871,11 +1317,11 @@ describe("createTracebackInfoAtom", () => {
|
|
|
3871
1317
|
data: [{ type: "syntax", msg: "Syntax error", lineno: 1 }],
|
|
3872
1318
|
mimetype: "application/vnd.marimo+error",
|
|
3873
1319
|
},
|
|
3874
|
-
status: "running",
|
|
3875
1320
|
},
|
|
3876
1321
|
},
|
|
3877
1322
|
}),
|
|
3878
1323
|
);
|
|
1324
|
+
MockExecutions.seed(store, [MockExecutions.running(cellId("cell1"))]);
|
|
3879
1325
|
|
|
3880
1326
|
const tracebackAtom = exportedForTesting.createTracebackInfoAtom(
|
|
3881
1327
|
cellId("cell1"),
|
|
@@ -3886,31 +1332,9 @@ describe("createTracebackInfoAtom", () => {
|
|
|
3886
1332
|
});
|
|
3887
1333
|
});
|
|
3888
1334
|
|
|
3889
|
-
describe("
|
|
1335
|
+
describe("kernel-ready", () => {
|
|
3890
1336
|
const CELL_A = cellId("A");
|
|
3891
1337
|
const CELL_B = cellId("B");
|
|
3892
|
-
const newCells: CellData[] = [
|
|
3893
|
-
{
|
|
3894
|
-
id: CELL_A,
|
|
3895
|
-
name: "a",
|
|
3896
|
-
code: "1",
|
|
3897
|
-
edited: false,
|
|
3898
|
-
lastCodeRun: null,
|
|
3899
|
-
lastExecutionTime: null,
|
|
3900
|
-
config: { hide_code: false, disabled: false, column: null },
|
|
3901
|
-
serializedEditorState: null,
|
|
3902
|
-
},
|
|
3903
|
-
{
|
|
3904
|
-
id: CELL_B,
|
|
3905
|
-
name: "b",
|
|
3906
|
-
code: "2",
|
|
3907
|
-
edited: false,
|
|
3908
|
-
lastCodeRun: null,
|
|
3909
|
-
lastExecutionTime: null,
|
|
3910
|
-
config: { hide_code: false, disabled: false, column: null },
|
|
3911
|
-
serializedEditorState: null,
|
|
3912
|
-
},
|
|
3913
|
-
];
|
|
3914
1338
|
|
|
3915
1339
|
const hydratedState = () =>
|
|
3916
1340
|
MockNotebook.notebookState({
|
|
@@ -3940,44 +1364,74 @@ describe("setCells snapshot preservation", () => {
|
|
|
3940
1364
|
},
|
|
3941
1365
|
});
|
|
3942
1366
|
|
|
3943
|
-
|
|
3944
|
-
const { isWasm } = await import("@/core/wasm/utils");
|
|
3945
|
-
vi.mocked(isWasm).mockReturnValue(true);
|
|
3946
|
-
});
|
|
3947
|
-
|
|
3948
|
-
it("preserves hydrated output in WASM", () => {
|
|
1367
|
+
it("resetCellRuntimes starts every cell's runtime over", () => {
|
|
3949
1368
|
const next = exportedForTesting.reducer(hydratedState(), {
|
|
3950
|
-
type: "
|
|
3951
|
-
payload:
|
|
1369
|
+
type: "resetCellRuntimes",
|
|
1370
|
+
payload: undefined,
|
|
3952
1371
|
});
|
|
3953
1372
|
|
|
3954
|
-
expect(next.cellRuntime[CELL_A].output).
|
|
3955
|
-
|
|
1373
|
+
expect(next.cellRuntime[CELL_A].output).toBeNull();
|
|
1374
|
+
expect(next.cellRuntime[CELL_B].consoleOutputs).toEqual([]);
|
|
1375
|
+
});
|
|
1376
|
+
|
|
1377
|
+
it("resetCellRuntimes starts the scratch cell over too", () => {
|
|
1378
|
+
const state = MockNotebook.notebookState({
|
|
1379
|
+
cellData: { [CELL_A]: { id: CELL_A, code: "1" } },
|
|
1380
|
+
cellRuntime: {
|
|
1381
|
+
[SCRATCH_CELL_ID]: {
|
|
1382
|
+
output: {
|
|
1383
|
+
channel: "output",
|
|
1384
|
+
mimetype: "text/plain",
|
|
1385
|
+
data: "scratch",
|
|
1386
|
+
timestamp: 0,
|
|
1387
|
+
},
|
|
1388
|
+
},
|
|
1389
|
+
},
|
|
3956
1390
|
});
|
|
1391
|
+
const next = exportedForTesting.reducer(state, {
|
|
1392
|
+
type: "resetCellRuntimes",
|
|
1393
|
+
payload: undefined,
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
expect(next.cellRuntime[SCRATCH_CELL_ID].output).toBeNull();
|
|
3957
1397
|
});
|
|
3958
1398
|
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
1399
|
+
describe("resetCellRuntimes in WASM", () => {
|
|
1400
|
+
beforeEach(async () => {
|
|
1401
|
+
const { isWasm } = await import("@/core/wasm/utils");
|
|
1402
|
+
vi.mocked(isWasm).mockReturnValue(true);
|
|
3963
1403
|
});
|
|
3964
1404
|
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
1405
|
+
afterEach(async () => {
|
|
1406
|
+
const { isWasm } = await import("@/core/wasm/utils");
|
|
1407
|
+
vi.mocked(isWasm).mockReturnValue(false);
|
|
3968
1408
|
});
|
|
3969
|
-
});
|
|
3970
1409
|
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
1410
|
+
it("keeps hydrated outputs and console", () => {
|
|
1411
|
+
const next = exportedForTesting.reducer(hydratedState(), {
|
|
1412
|
+
type: "resetCellRuntimes",
|
|
1413
|
+
payload: undefined,
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1416
|
+
expect(next.cellRuntime[CELL_A].output).toMatchObject({
|
|
1417
|
+
data: "hydrated-A",
|
|
1418
|
+
});
|
|
1419
|
+
expect(next.cellRuntime[CELL_B].consoleOutputs[0]).toMatchObject({
|
|
1420
|
+
data: "hydrated-B-stdout",
|
|
1421
|
+
});
|
|
3976
1422
|
});
|
|
3977
1423
|
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
1424
|
+
it("starts cells with no prior runtime over", () => {
|
|
1425
|
+
const state = MockNotebook.notebookState({
|
|
1426
|
+
cellData: { [CELL_A]: { id: CELL_A, code: "1" } },
|
|
1427
|
+
});
|
|
1428
|
+
const next = exportedForTesting.reducer(state, {
|
|
1429
|
+
type: "resetCellRuntimes",
|
|
1430
|
+
payload: undefined,
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
expect(next.cellRuntime[CELL_A].output).toBeNull();
|
|
1434
|
+
expect(next.cellRuntime[CELL_A].consoleOutputs).toEqual([]);
|
|
1435
|
+
});
|
|
3982
1436
|
});
|
|
3983
1437
|
});
|