@marimo-team/islands 0.25.3-dev30 → 0.25.3-dev302
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-DJnSxHJB.js} +153 -177
- package/dist/{ErrorBoundary-2Tp_7IgE.js → ErrorBoundary-BDEkm7xA.js} +79 -85
- package/dist/{ImageComparisonComponent-uU8FSKZE.js → ImageComparisonComponent-DgvSuY9B.js} +20 -20
- package/dist/{Plot-DdYOe1UK.js → Plot-Bfd0pJea.js} +2474 -3107
- package/dist/_baseSet-Bd5zh2yg.js +327 -0
- package/dist/{abnfDiagram-VCTEODGH-z_OSynK8.js → abnfDiagram-VCTEODGH-CR0U5hup.js} +5 -5
- package/dist/any-language-editor-C5dsTpeB.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-Bc_fbI1Q.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-efcK_v3t.js +507 -0
- package/dist/assets/__vite-browser-external-DzTYIHH_.js +1 -0
- package/dist/assets/worker-BH08I2Il.js +171 -0
- package/dist/{blockDiagram-I7D4REHJ-Cg25UrxT.js → blockDiagram-I7D4REHJ-B4cvqWJn.js} +28 -39
- package/dist/{brainfuck-BQCYDheZ.js → brainfuck-UPAij4U9.js} +1 -1
- package/dist/{button-CvjkwdSk.js → button-BuSV-mLI.js} +64 -64
- package/dist/{c4Diagram-7LVT6UL2-BxFgrnNV.js → c4Diagram-7LVT6UL2-k-4SLDdM.js} +8 -8
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-BiN90k7v.js} +2 -2
- package/dist/{channel-CPObtJXj.js → channel-CuTaWMxU.js} +1 -1
- package/dist/{chat-ui-BeKQyQQI.js → chat-ui-C4iLRzY0.js} +2142 -1869
- package/dist/{check-BMKBBrdc.js → check-DCQEEsUn.js} +1 -1
- package/dist/{chunk-4HAMMTFA-D4eFPyFh.js → chunk-4HAMMTFA-Bk_5S_m9.js} +6 -6
- package/dist/{chunk-75Z2AOVW-D7gxIs2Q.js → chunk-75Z2AOVW-9jQIEAxd.js} +4 -4
- package/dist/{chunk-DU6HZSFF-BwiyaNpg.js → chunk-DU6HZSFF-B20LZ-hE.js} +14 -22
- package/dist/{chunk-F27PBJKO-ufseIn5y.js → chunk-F27PBJKO-YjRXlNkT.js} +3 -3
- package/dist/{chunk-FOHPRMQF-BpYR8RqP.js → chunk-FOHPRMQF-ezmr_yWy.js} +49 -58
- package/dist/{chunk-GMAD6QVW-BhaJx0X3.js → chunk-GMAD6QVW-DokpSFdf.js} +16 -75
- package/dist/{chunk-GVQU2GXP-Cwbt-lF0.js → chunk-GVQU2GXP-DGvySV5W.js} +3 -3
- package/dist/{chunk-IMKFNOWR-aoSFasqF.js → chunk-IMKFNOWR-y9z5oeAY.js} +8 -8
- package/dist/{chunk-L3NEJ4N5-n-zgIVSy.js → chunk-L3NEJ4N5-D9-ekjZc.js} +6 -6
- package/dist/{chunk-OSK3NFVY-DXa-Cxbn.js → chunk-OSK3NFVY-p7meGiY-.js} +8 -8
- package/dist/{chunk-P2QGCYS3-B_Zd3-X0.js → chunk-P2QGCYS3-74rxrEwb.js} +1 -1
- package/dist/{chunk-POPQ4Y6H-hYOXbYH_.js → chunk-POPQ4Y6H-EOTPk9Tj.js} +2 -2
- package/dist/{chunk-PWAF6VOD-CQw5qATZ.js → chunk-PWAF6VOD-oT_Qd2OU.js} +2 -2
- package/dist/{chunk-SHT3W25Y-CMaybO3O.js → chunk-SHT3W25Y-Tu-V-e_v.js} +10 -10
- package/dist/{chunk-SVP7TREG-BNBrTAw1.js → chunk-SVP7TREG-CJFxs5R_.js} +3 -3
- package/dist/{chunk-TICWLB2K-DXNxvUJn.js → chunk-TICWLB2K-zkTP7ya7.js} +10 -10
- package/dist/{chunk-XXDRQBXY-Dnl5VBqG.js → chunk-XXDRQBXY-BM-YIt-_.js} +1 -1
- package/dist/{chunk-YOKDWASO-DKplTrBY.js → chunk-YOKDWASO-KxncHymC.js} +153 -378
- package/dist/classDiagram-ZZMXUADV-DxJAZI0N.js +30 -0
- package/dist/classDiagram-v2-VYDZK3BY-TmHo2BpS.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-891-xGjh.js → code-visibility-NL_5uwhy.js} +43 -50
- package/dist/{coffeescript-C-eFwH5N.js → coffeescript-D6UgrGgo.js} +1 -1
- package/dist/{common-_IunO2z-.js → common-M3iB2q2_.js} +10624 -10120
- package/dist/{commonlisp-CyaNXrJR.js → commonlisp-B0ChVjnu.js} +1 -1
- package/dist/{compiler-runtime-CldRdSsv.js → compiler-runtime-DNezxW8I.js} +2 -2
- package/dist/config-BG2qKzDg.js +633 -0
- package/dist/{copy-icon-BgUO8jsi.js → copy-icon-oHFcxX_y.js} +21 -22
- package/dist/{cose-bilkent-JH36ORCC-_LyRKVqm.js → cose-bilkent-JH36ORCC-B_Oz4vMP.js} +58 -71
- package/dist/createReducer-DHfURLCk.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-Eb40hmhD.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-_paaVwit.js} +14 -16
- package/dist/{data-grid-overlay-editor-TVf1Kaxm.js → data-grid-overlay-editor-BaQAbdKk.js} +5 -5
- package/dist/{data-grid-types-0PJ-9N5n.js → data-grid-types-CSElxhxo.js} +1 -1
- package/dist/{debounce-C3jyATpc.js → debounce-DrhhziJv.js} +2 -2
- package/dist/{diagram-S7CK7UJ4-PwwcUOHP.js → diagram-S7CK7UJ4-BtKJm1_4.js} +7 -15
- package/dist/{diagram-UQ7AKVKN-CvJbL_IM.js → diagram-UQ7AKVKN-DQbxhEMd.js} +5 -5
- package/dist/{diagram-VSXAHHWV-BJWcVVJY.js → diagram-VSXAHHWV-CodTjaL3.js} +6 -6
- package/dist/{diagram-VX7I27RA-B5RkqnzN.js → diagram-VX7I27RA-DITDIfGC.js} +7 -7
- package/dist/{diagram-Z3DM3KII-CyijwTR2.js → diagram-Z3DM3KII-Ct9_zo6F.js} +5 -5
- package/dist/{dialog-Cc479ZEH.js → dialog-BIUdMLIS.js} +36 -36
- 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-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-Lm-D-Vr6.js → dist-Du4PgaYp.js} +2 -2
- 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-CAejOChE.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-6cOntwfv.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-CJiOER41.js} +14 -14
- package/dist/{erlang-AdO1-xtV.js → erlang-2KpKpfC7.js} +1 -1
- package/dist/{error-banner-CFPHFw4h.js → error-banner-DGOrmBk5.js} +91 -91
- package/dist/error-entries-BWmleiL0.js +2581 -0
- package/dist/{esm-G4Fhsgng.js → esm-BUoz9Vvv.js} +4 -4
- package/dist/{esm-AMFssoNp.js → esm-BvhFNYzM.js} +333 -333
- 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-CnhSwoRZ.js +370 -0
- package/dist/flowDiagram-HODETNUW-1lPBEUuW.js +15 -0
- package/dist/{formats-DRHUWwSK.js → formats-qhBmYb0l.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-DyUab7aO.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-BPeDECwG.js} +4 -4
- package/dist/{glide-data-editor-ugYWecYd.js → glide-data-editor-Ca0ThLaf.js} +6619 -2875
- package/dist/{glide-utils-pisbYVjH.js → glide-utils-C4TKZeBA.js} +109 -78
- package/dist/{globals-BdBjL67a.js → globals-CI7fOwRe.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-KPVGNVTW-3Ziwfz-V.js → highlighted-body-KPVGNVTW-XbLtWlYz.js} +4 -4
- package/dist/{error-entries-CnqKxhU9.js → html-to-image-B8hE6HIH.js} +26032 -26377
- 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-C6K4tri5.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-DwcwgRNH.js} +5 -7
- package/dist/{javascript-BfNytHiM.js → javascript-BQtCoAFy.js} +2 -2
- package/dist/{journeyDiagram-3NMN7TZE-BaLqn-dZ.js → journeyDiagram-3NMN7TZE-D7hcb3Vx.js} +4 -4
- package/dist/{jsx-runtime-3BD1kT0s.js → jsx-runtime-6ZiU38At.js} +1 -1
- package/dist/{julia--tLIAG7q.js → julia-BfgtHJE5.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-BLhvu8o4.js → kanban-definition-UXKFOSKX-E489OMdc.js} +10 -10
- package/dist/{katex-BIdZGsyO.js → katex-BmPSeP5t.js} +15 -24
- package/dist/{linear-DWERh7eI.js → linear-BhKepphY.js} +2 -3
- package/dist/{livescript-CVPfYnY_.js → livescript-gIdRPKtg.js} +1 -1
- package/dist/{loader-BPdQhmlq.js → loader-BIlwkY0d.js} +3 -3
- package/dist/{lua-4Fa-T-qq.js → lua-CxFpWvnv.js} +2 -2
- package/dist/main.js +10380 -8501
- 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-DMPMkVqY.js} +170 -176
- package/dist/mermaid-HWGCJPDP-_lKUMvTM.js +1 -0
- package/dist/{mermaid-parser.core-DxuSfYwJ.js → mermaid-parser.core-DtOnl7m4.js} +19 -25
- package/dist/{mhchem-CdWPJK6g.js → mhchem-CjWbCsjZ.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-DWHjasOp.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-I4AHjcHG.js → number-overlay-editor-uJBCKZNU.js} +14 -19
- 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-COjcPOZT.js} +5 -5
- package/dist/pencil-BUfnNZAE.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-BHAVZ38h.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/{process-output-DgQrilBD.js → process-output-DZDL_j1a.js} +5 -5
- 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-DLJJzlPi.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-94ThFyKX.js} +5 -5
- package/dist/{react-sHtZdjeP.js → react-CHbZqgBF.js} +1 -1
- package/dist/{react-dom-DUmH0GXv.js → react-dom-DhWGW7e0.js} +3 -3
- package/dist/{react-vega-BDpbvBCb.js → react-vega-DVr24mNk.js} +8514 -8597
- package/dist/{requirementDiagram-BXWQKSXE--J8vyfm-.js → requirementDiagram-BXWQKSXE-CpF-Fxbb.js} +13 -13
- package/dist/{reveal-component-Bb5vzlMs.js → reveal-component-C8v8DMO2.js} +1171 -1284
- 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-Bd7wvmbF.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-XmXyen3r.js +1200 -0
- package/dist/{semaphore-89jsoHtS.js → semaphore-8KhQouXt.js} +4 -5
- package/dist/{sequenceDiagram-WJ2MYXX4-CiQbn62x.js → sequenceDiagram-WJ2MYXX4-CvANK2x7.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-CSS9g9Su.js} +42 -12
- package/dist/{src-CA_m4ONl.js → src-D5uZaZib.js} +8 -14
- package/dist/{stateDiagram-D77RDMKH-DVEeGs5b.js → stateDiagram-D77RDMKH-WHuJ4mJL.js} +18 -18
- package/dist/stateDiagram-v2-MP3YSRHH-DbO7lwYq.js +30 -0
- package/dist/static-state-Dtocd9UO.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-CS2s29Vo.js} +37 -59
- package/dist/swimlanesDiagram-VR7AAH4N-CXaA1vQg.js +30 -0
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-FBPvIqLf.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-Cc-G3e31.js} +2 -2
- package/dist/{timeline-definition-24CTP7MA-DLRUNVAx.js → timeline-definition-24CTP7MA-B-SQMg5h.js} +5 -5
- package/dist/toast-xEFvuGpt.js +491 -0
- package/dist/{toml-CaUN7UHo.js → toml-B0B7UAba.js} +1 -1
- package/dist/{tooltip-CtBZ5q8p.js → tooltip-BekOCQ3v.js} +326 -302
- 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-DyrKLdSB.js +7602 -0
- package/dist/{use-vega-container-remeasure-Bz4PZMtt.js → use-vega-container-remeasure-DFBTESqc.js} +4 -8
- package/dist/{useAsyncData-BneN349z.js → useAsyncData-DMBliR6D.js} +21 -20
- package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-Brx-S2sN.js} +4 -4
- package/dist/{useDeepCompareMemoize-Z_7R8wTt.js → useDeepCompareMemoize-CxywEb3a.js} +3 -3
- package/dist/useEvent-xDnF2X04.js +19 -0
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities--px_wpZL.js} +2 -2
- package/dist/useLifecycle-BMlFy2yY.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-DwqGfN3_.js} +167 -172
- package/dist/{vega-embed-container-BgKnsDbB.js → vega-embed-container-DAT8OHp9.js} +7 -7
- package/dist/{vega-loader.browser-CpbZAXub.js → vega-loader.browser-Cnf7IHA8.js} +236 -239
- package/dist/{velocity-CZKOFbOI.js → velocity-2Doc6dgJ.js} +1 -1
- package/dist/{vennDiagram-4TSXK5OY-CypgoBVZ.js → vennDiagram-4TSXK5OY-etEFgvaG.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-BEQN7g62.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-D8-e5Z0R.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 +17 -21
- package/src/__mocks__/document.tsx +63 -0
- package/src/__mocks__/executions.ts +197 -0
- package/src/__mocks__/notebook.ts +3 -7
- package/src/__mocks__/partial.ts +26 -0
- package/src/__mocks__/requests.ts +1 -4
- 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 +1 -21
- 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__/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 +216 -294
- 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/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/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 +1 -1
- package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
- package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
- 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 +2 -2
- package/src/components/editor/cell/__tests__/useRunCells.test.tsx +169 -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 +4 -1
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +65 -169
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- 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 +49 -8
- 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 +92 -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 +1 -1
- 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 +126 -152
- 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 +33 -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 +32 -100
- 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 +37 -34
- 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 +44 -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 +25 -1
- package/src/components/ui/range-slider.tsx +22 -9
- package/src/components/ui/toast.tsx +1 -1
- package/src/core/MarimoApp.tsx +3 -1
- package/src/core/ai/__tests__/staged-cells.test.ts +89 -608
- 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 +4 -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 +394 -2926
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -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 +47 -43
- package/src/core/cells/arrange.ts +529 -0
- package/src/core/cells/cell.ts +78 -146
- package/src/core/cells/cells.ts +107 -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 +2 -2
- 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 +22 -28
- 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 +98 -0
- package/src/core/executions/__tests__/freshness.test.ts +482 -0
- package/src/core/executions/__tests__/hooks.test.tsx +151 -0
- package/src/core/executions/__tests__/output.test.ts +266 -0
- package/src/core/executions/__tests__/select.test.ts +268 -0
- package/src/core/executions/atoms.ts +263 -0
- package/src/core/executions/freshness.ts +171 -0
- package/src/core/executions/hooks.ts +86 -0
- package/src/core/executions/index.ts +48 -0
- package/src/core/executions/output.ts +242 -0
- package/src/core/executions/select.ts +175 -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 +85 -27
- package/src/core/islands/bootstrap.ts +49 -54
- package/src/core/islands/bridge.ts +84 -25
- package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
- 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 +33 -33
- 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-lazy.test.ts +6 -8
- package/src/core/network/connection-notice.ts +1 -1
- package/src/core/network/connection.ts +1 -1
- package/src/core/network/requests-lazy.ts +5 -8
- package/src/core/network/requests-network.ts +5 -31
- package/src/core/network/requests-static.ts +1 -4
- package/src/core/network/requests-toasting.tsx +1 -4
- package/src/core/network/types.ts +6 -14
- 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 +247 -0
- package/src/core/notebook/document/__tests__/test-notebook.ts +149 -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 +369 -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 +79 -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 +19 -0
- package/src/core/notebook/replica/connection.ts +42 -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 +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +32 -74
- package/src/core/runtime/adapter.ts +5 -5
- package/src/core/runtime/config.ts +2 -2
- package/src/core/runtime/runtime.ts +33 -46
- package/src/core/runtime/types.ts +0 -2
- 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 +245 -262
- package/src/core/session/active-notebook.ts +28 -0
- package/src/core/session/backend.ts +123 -0
- 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 +80 -67
- 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 +173 -0
- package/src/core/transports/wasm.ts +97 -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 +210 -64
- package/src/core/wasm/__tests__/worker.test.ts +188 -0
- package/src/core/wasm/bridge.ts +120 -73
- 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 +30 -18
- package/src/core/wasm/worker/worker.ts +118 -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/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 +20 -15
- 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 +34 -13
- 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 +6 -8
- package/src/plugins/impl/__tests__/DataEditorPlugin.test.ts +93 -4
- 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 +24 -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 +120 -4
- 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 +74 -12
- 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/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/DownloadPlugin.tsx +7 -11
- package/src/plugins/layout/LazyPlugin.tsx +7 -4
- package/src/plugins/layout/RoutesPlugin.tsx +1 -1
- package/src/plugins/layout/__test__/DownloadPlugin.test.tsx +205 -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/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/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/feedback-button-DlBBr16w.js +0 -379
- 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/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/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/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/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/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
- /package/src/core/{websocket → session}/connection-utils.ts +0 -0
|
@@ -1,32 +1,37 @@
|
|
|
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";
|
|
21
|
+
import {
|
|
22
|
+
notebookQueuedOrRunningCountAtom,
|
|
23
|
+
submitCells,
|
|
24
|
+
} from "@/core/executions";
|
|
25
|
+
import { store } from "@/core/state/jotai";
|
|
17
26
|
import { MockNotebook } from "@/__mocks__/notebook";
|
|
18
27
|
import { cellId } from "@/__tests__/branded";
|
|
19
28
|
import type { CellHandle } from "@/components/editor/notebook-cell";
|
|
20
|
-
import { CellId, SCRATCH_CELL_ID
|
|
29
|
+
import { CellId, SCRATCH_CELL_ID } from "@/core/cells/ids";
|
|
21
30
|
import { foldAllBulk, unfoldAllBulk } from "@/core/codemirror/editing/commands";
|
|
22
31
|
import { adaptiveLanguageConfiguration } from "@/core/codemirror/language/extension";
|
|
23
32
|
import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
|
|
24
33
|
import type { OutputMessage } from "@/core/kernel/messages";
|
|
25
|
-
import {
|
|
26
|
-
type CollapsibleTree,
|
|
27
|
-
MultiColumn,
|
|
28
|
-
type CellColumnId,
|
|
29
|
-
} from "@/utils/id-tree";
|
|
34
|
+
import type { CellConfig } from "@/core/network/types";
|
|
30
35
|
import type { Seconds } from "@/utils/time";
|
|
31
36
|
import {
|
|
32
37
|
exportedForTesting,
|
|
@@ -34,13 +39,12 @@ import {
|
|
|
34
39
|
type NotebookState,
|
|
35
40
|
notebookAtom,
|
|
36
41
|
} from "../cells";
|
|
37
|
-
import { exportedForTesting as documentTransactionTestExports } from "../document-changes";
|
|
38
42
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
type CellData,
|
|
44
|
+
createCell,
|
|
45
|
+
createCellConfig,
|
|
46
|
+
createCellRuntimeState,
|
|
47
|
+
} from "../types";
|
|
44
48
|
|
|
45
49
|
vi.mock("@/core/codemirror/editing/commands", () => ({
|
|
46
50
|
foldAllBulk: vi.fn(),
|
|
@@ -60,9 +64,6 @@ vi.mock("../scrollCellIntoView", async (importOriginal) => {
|
|
|
60
64
|
};
|
|
61
65
|
});
|
|
62
66
|
|
|
63
|
-
const FIRST_COLUMN = 0;
|
|
64
|
-
const SECOND_COLUMN = 1;
|
|
65
|
-
|
|
66
67
|
const { initialNotebookState, reducer, createActions } = exportedForTesting;
|
|
67
68
|
|
|
68
69
|
function formatCells(notebook: NotebookState) {
|
|
@@ -78,14 +79,7 @@ function formatCells(notebook: NotebookState) {
|
|
|
78
79
|
const cells = cellsId.map((cellId) => cellData[cellId]);
|
|
79
80
|
return cells.map((cell) => printCell(cell)).join("\n\n");
|
|
80
81
|
};
|
|
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));
|
|
82
|
+
return wrap(printCells(cellIds));
|
|
89
83
|
}
|
|
90
84
|
|
|
91
85
|
function createEditor(content: string) {
|
|
@@ -96,6 +90,7 @@ function createEditor(content: string) {
|
|
|
96
90
|
adaptiveLanguageConfiguration({
|
|
97
91
|
cellId: cellId("cell1"),
|
|
98
92
|
completionConfig: {
|
|
93
|
+
...defaultUserConfig().completion,
|
|
99
94
|
activate_on_typing: true,
|
|
100
95
|
signature_hint_on_typing: false,
|
|
101
96
|
copilot: false,
|
|
@@ -103,7 +98,7 @@ function createEditor(content: string) {
|
|
|
103
98
|
},
|
|
104
99
|
hotkeys: new OverridingHotkeyProvider({}),
|
|
105
100
|
placeholderType: "marimo-import",
|
|
106
|
-
lspConfig: {},
|
|
101
|
+
lspConfig: { ...defaultUserConfig().language_servers },
|
|
107
102
|
}),
|
|
108
103
|
],
|
|
109
104
|
});
|
|
@@ -121,8 +116,7 @@ describe("cell reducer", () => {
|
|
|
121
116
|
let cells: ReturnType<typeof flattenTopLevelNotebookCells>;
|
|
122
117
|
let firstCellId: CellId;
|
|
123
118
|
|
|
124
|
-
const
|
|
125
|
-
state = reducer(state, action);
|
|
119
|
+
const mountEditors = () => {
|
|
126
120
|
for (const [cellIdString, handle] of Object.entries(state.cellHandles)) {
|
|
127
121
|
// @ts-expect-error - Typescript Object.entries doesn't know that keys are CellId
|
|
128
122
|
const cid: CellId = cellIdString;
|
|
@@ -136,7 +130,83 @@ describe("cell reducer", () => {
|
|
|
136
130
|
}
|
|
137
131
|
}
|
|
138
132
|
cells = flattenTopLevelNotebookCells(state);
|
|
139
|
-
}
|
|
133
|
+
};
|
|
134
|
+
const actions = createActions((action) => {
|
|
135
|
+
state = reducer(state, action);
|
|
136
|
+
mountEditors();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
/** Put a cell into the notebook the way the document would. */
|
|
140
|
+
function seedCell({
|
|
141
|
+
cellId,
|
|
142
|
+
before,
|
|
143
|
+
code = "",
|
|
144
|
+
name,
|
|
145
|
+
config,
|
|
146
|
+
newCellId,
|
|
147
|
+
hideCode,
|
|
148
|
+
autoFocus = true,
|
|
149
|
+
}: {
|
|
150
|
+
cellId: CellId | "__end__";
|
|
151
|
+
before: boolean;
|
|
152
|
+
code?: string;
|
|
153
|
+
name?: string;
|
|
154
|
+
config?: CellConfig;
|
|
155
|
+
newCellId?: CellId;
|
|
156
|
+
hideCode?: boolean;
|
|
157
|
+
autoFocus?: boolean;
|
|
158
|
+
}): CellId {
|
|
159
|
+
const cellIndex =
|
|
160
|
+
cellId === "__end__"
|
|
161
|
+
? state.cellIds.length
|
|
162
|
+
: state.cellIds.indexOf(cellId);
|
|
163
|
+
const id = newCellId ?? CellId.create();
|
|
164
|
+
const cellIds = [...state.cellIds];
|
|
165
|
+
cellIds.splice(before ? cellIndex : cellIndex + 1, 0, id);
|
|
166
|
+
state = {
|
|
167
|
+
...state,
|
|
168
|
+
cellIds,
|
|
169
|
+
cellData: {
|
|
170
|
+
...state.cellData,
|
|
171
|
+
[id]: createCell({
|
|
172
|
+
id,
|
|
173
|
+
code,
|
|
174
|
+
name,
|
|
175
|
+
config: createCellConfig({
|
|
176
|
+
...config,
|
|
177
|
+
...(hideCode != null && { hide_code: hideCode }),
|
|
178
|
+
}),
|
|
179
|
+
}),
|
|
180
|
+
},
|
|
181
|
+
cellRuntime: { ...state.cellRuntime, [id]: createCellRuntimeState() },
|
|
182
|
+
cellHandles: { ...state.cellHandles, [id]: createRef() },
|
|
183
|
+
scrollKey: autoFocus ? id : null,
|
|
184
|
+
};
|
|
185
|
+
mountEditors();
|
|
186
|
+
return id;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Edit a cell's code as the document delivers it. */
|
|
190
|
+
function editCode(cellId: CellId, code: string) {
|
|
191
|
+
const cells = state.cellIds.map((id) => {
|
|
192
|
+
const cell = state.cellData[id];
|
|
193
|
+
return {
|
|
194
|
+
id,
|
|
195
|
+
code: id === cellId ? code : cell.code,
|
|
196
|
+
name: cell.name,
|
|
197
|
+
config: {
|
|
198
|
+
column: cell.config.column ?? null,
|
|
199
|
+
disabled: cell.config.disabled ?? false,
|
|
200
|
+
hide_code: cell.config.hide_code ?? false,
|
|
201
|
+
expand_output: cell.config.expand_output ?? false,
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
actions.reconcileDocument({
|
|
206
|
+
order: state.cellIds,
|
|
207
|
+
cells: new Map(cells.map((cell) => [cell.id, cell])),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
140
210
|
|
|
141
211
|
let i = 0;
|
|
142
212
|
const originalCreate = CellId.create.bind(CellId);
|
|
@@ -151,852 +221,214 @@ describe("cell reducer", () => {
|
|
|
151
221
|
i = 0;
|
|
152
222
|
|
|
153
223
|
state = initialNotebookState();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
firstCellId = state.cellIds.inOrderIds[0];
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
afterEach(() => {
|
|
160
|
-
documentTransactionTestExports.cancelPendingChanges();
|
|
224
|
+
seedCell({ cellId: "__end__", before: false });
|
|
225
|
+
firstCellId = state.cellIds[0];
|
|
161
226
|
});
|
|
162
227
|
|
|
163
228
|
afterAll(() => {
|
|
164
229
|
CellId.create = originalCreate;
|
|
165
230
|
});
|
|
166
231
|
|
|
167
|
-
it("can
|
|
168
|
-
|
|
169
|
-
cellId: firstCellId,
|
|
170
|
-
before: false,
|
|
171
|
-
});
|
|
232
|
+
it("can update a cell", () => {
|
|
233
|
+
editCode(firstCellId, "import numpy as np");
|
|
172
234
|
expect(formatCells(state)).toMatchInlineSnapshot(`
|
|
173
235
|
"
|
|
174
|
-
[0] ''
|
|
175
|
-
|
|
176
|
-
[1] ''
|
|
236
|
+
[0] 'import numpy as np'
|
|
177
237
|
"
|
|
178
238
|
`);
|
|
179
239
|
});
|
|
180
240
|
|
|
181
|
-
it("
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
241
|
+
it("keeps error evidence after an edit and a new queued run", () => {
|
|
242
|
+
const code = "raise ValueError('old failure')";
|
|
243
|
+
const output: OutputMessage = {
|
|
244
|
+
channel: "marimo-error",
|
|
245
|
+
mimetype: "application/vnd.marimo+error",
|
|
246
|
+
data: [
|
|
247
|
+
{
|
|
248
|
+
type: "exception",
|
|
249
|
+
msg: "old failure",
|
|
250
|
+
exception_type: "ValueError",
|
|
251
|
+
raising_cell: null,
|
|
252
|
+
traceback: "<pre>ValueError: old failure</pre>",
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
code,
|
|
256
|
+
timestamp: 1,
|
|
257
|
+
};
|
|
258
|
+
actions.handleCellMessage({
|
|
259
|
+
cell_id: firstCellId,
|
|
260
|
+
output,
|
|
261
|
+
console: {
|
|
262
|
+
channel: "stderr",
|
|
263
|
+
mimetype: "application/vnd.marimo+traceback",
|
|
264
|
+
data: "<pre>ValueError: old failure</pre>",
|
|
265
|
+
code,
|
|
266
|
+
timestamp: 1,
|
|
267
|
+
},
|
|
268
|
+
status: "idle",
|
|
269
|
+
timestamp: 1,
|
|
186
270
|
});
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
271
|
+
editCode(firstCellId, "print('new code')");
|
|
272
|
+
actions.prepareForRun({ cellId: firstCellId });
|
|
273
|
+
actions.handleCellMessage({
|
|
274
|
+
cell_id: firstCellId,
|
|
275
|
+
output: null,
|
|
276
|
+
console: null,
|
|
277
|
+
status: "queued",
|
|
278
|
+
timestamp: 2,
|
|
279
|
+
});
|
|
280
|
+
const runtime = state.cellRuntime[firstCellId];
|
|
281
|
+
expect(runtime.output).toEqual(output);
|
|
282
|
+
expect(runtime.consoleOutputs[0].code).toBe(code);
|
|
283
|
+
expect(runtime.consoleOutputs[0].data).toContain("old failure");
|
|
284
|
+
});
|
|
190
285
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
286
|
+
it("can run cell and receive cell messages", () => {
|
|
287
|
+
// HAPPY PATH
|
|
288
|
+
/////////////////
|
|
289
|
+
// Initial state
|
|
290
|
+
let cell = cells[0];
|
|
291
|
+
expect(cell).toMatchSnapshot("initial state");
|
|
194
292
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
expect(
|
|
199
|
-
});
|
|
293
|
+
// Update code
|
|
294
|
+
editCode(firstCellId, "import marimo as mo");
|
|
295
|
+
cell = cells[0];
|
|
296
|
+
expect(cell).toMatchSnapshot("code edited");
|
|
200
297
|
|
|
201
|
-
|
|
202
|
-
actions.
|
|
298
|
+
// Prepare for run
|
|
299
|
+
actions.prepareForRun({
|
|
203
300
|
cellId: firstCellId,
|
|
204
|
-
before: true,
|
|
205
301
|
});
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
[1] ''
|
|
302
|
+
cell = cells[0];
|
|
303
|
+
expect(cell).toMatchSnapshot("prepared for run");
|
|
209
304
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
305
|
+
// Receive queued messages
|
|
306
|
+
actions.handleCellMessage({
|
|
307
|
+
cell_id: firstCellId,
|
|
308
|
+
output: undefined,
|
|
309
|
+
console: null,
|
|
310
|
+
status: "queued",
|
|
311
|
+
timestamp: new Date(10).getTime() as Seconds,
|
|
312
|
+
});
|
|
313
|
+
cell = cells[0];
|
|
314
|
+
expect(cell).toMatchSnapshot("queued message received");
|
|
214
315
|
|
|
215
|
-
|
|
216
|
-
actions.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
316
|
+
// Receive running messages
|
|
317
|
+
actions.handleCellMessage({
|
|
318
|
+
cell_id: firstCellId,
|
|
319
|
+
output: undefined,
|
|
320
|
+
console: null,
|
|
321
|
+
status: "running",
|
|
322
|
+
timestamp: new Date(20).getTime() as Seconds,
|
|
222
323
|
});
|
|
223
|
-
|
|
224
|
-
expect(
|
|
225
|
-
expect(state.cellData[newCellId].config.hide_code).toBe(true);
|
|
226
|
-
expect(state.cellData[newCellId].config.disabled).toBe(false);
|
|
227
|
-
});
|
|
324
|
+
cell = cells[0];
|
|
325
|
+
expect(cell).toMatchSnapshot("running message received");
|
|
228
326
|
|
|
229
|
-
|
|
230
|
-
actions.
|
|
231
|
-
|
|
232
|
-
|
|
327
|
+
// Console messages shouldn't transition status
|
|
328
|
+
actions.handleCellMessage({
|
|
329
|
+
cell_id: firstCellId,
|
|
330
|
+
output: undefined,
|
|
331
|
+
console: {
|
|
332
|
+
channel: "stdout",
|
|
333
|
+
mimetype: "text/plain",
|
|
334
|
+
data: "hello!",
|
|
335
|
+
timestamp: 0,
|
|
336
|
+
},
|
|
337
|
+
status: undefined,
|
|
338
|
+
timestamp: new Date(22).getTime() as Seconds,
|
|
233
339
|
});
|
|
234
|
-
|
|
235
|
-
|
|
340
|
+
cell = cells[0];
|
|
341
|
+
expect(cell).toMatchSnapshot("console message received");
|
|
342
|
+
|
|
343
|
+
// Receive output messages
|
|
344
|
+
actions.handleCellMessage({
|
|
345
|
+
cell_id: firstCellId,
|
|
346
|
+
output: {
|
|
347
|
+
channel: "output",
|
|
348
|
+
mimetype: "text/plain",
|
|
349
|
+
data: "ok",
|
|
350
|
+
timestamp: 0,
|
|
351
|
+
},
|
|
352
|
+
console: {
|
|
353
|
+
channel: "stdout",
|
|
354
|
+
mimetype: "text/plain",
|
|
355
|
+
data: "hello!",
|
|
356
|
+
timestamp: 0,
|
|
357
|
+
},
|
|
358
|
+
status: "idle",
|
|
359
|
+
timestamp: new Date(33).getTime() as Seconds,
|
|
236
360
|
});
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
[1] ''
|
|
240
|
-
"
|
|
241
|
-
`);
|
|
361
|
+
cell = cells[0];
|
|
362
|
+
expect(cell).toMatchSnapshot("output received");
|
|
242
363
|
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
364
|
+
// EDITING BACK AND FORTH
|
|
365
|
+
/////////////////
|
|
366
|
+
// Update code again
|
|
367
|
+
editCode(firstCellId, "import marimo as mo\nimport numpy");
|
|
368
|
+
cell = cells[0];
|
|
369
|
+
expect(cell).toMatchSnapshot("code edited again");
|
|
248
370
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
371
|
+
// Update code should be unedited
|
|
372
|
+
editCode(firstCellId, "import marimo as mo");
|
|
373
|
+
cell = cells[0];
|
|
374
|
+
expect(cell).toMatchSnapshot("code reverted");
|
|
252
375
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
376
|
+
// Update code should be edited again
|
|
377
|
+
editCode(firstCellId, "import marimo as mo\nimport numpy");
|
|
378
|
+
cell = cells[0];
|
|
379
|
+
expect(cell).toMatchSnapshot("code changed after revert");
|
|
256
380
|
|
|
257
|
-
|
|
258
|
-
|
|
381
|
+
// ERROR RESPONSE
|
|
382
|
+
/////////////////
|
|
383
|
+
// Prepare for run
|
|
384
|
+
actions.prepareForRun({
|
|
259
385
|
cellId: firstCellId,
|
|
260
|
-
before: false,
|
|
261
|
-
code: `df = mo.sql("""SELECT * FROM table""")`,
|
|
262
386
|
});
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
387
|
+
cell = cells[0];
|
|
388
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
389
|
+
// Queue
|
|
390
|
+
actions.handleCellMessage({
|
|
391
|
+
cell_id: firstCellId,
|
|
392
|
+
output: undefined,
|
|
393
|
+
console: null,
|
|
394
|
+
status: "queued",
|
|
395
|
+
timestamp: new Date(40).getTime() as Seconds,
|
|
266
396
|
});
|
|
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}""")`,
|
|
397
|
+
cell = cells[0];
|
|
398
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
399
|
+
// Running
|
|
400
|
+
actions.handleCellMessage({
|
|
401
|
+
cell_id: firstCellId,
|
|
402
|
+
output: undefined,
|
|
403
|
+
console: null,
|
|
404
|
+
status: "running",
|
|
405
|
+
timestamp: new Date(50).getTime() as Seconds,
|
|
290
406
|
});
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
407
|
+
cell = cells[0];
|
|
408
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
409
|
+
// Receive error
|
|
410
|
+
actions.handleCellMessage({
|
|
411
|
+
cell_id: firstCellId,
|
|
412
|
+
output: {
|
|
413
|
+
channel: "marimo-error",
|
|
414
|
+
mimetype: "application/vnd.marimo+error",
|
|
415
|
+
data: [
|
|
416
|
+
{ type: "exception", exception_type: "ValueError", msg: "Oh no!" },
|
|
417
|
+
],
|
|
418
|
+
timestamp: 0,
|
|
419
|
+
},
|
|
420
|
+
console: null,
|
|
421
|
+
status: "idle",
|
|
422
|
+
timestamp: new Date(61).getTime() as Seconds,
|
|
294
423
|
});
|
|
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
|
-
});
|
|
424
|
+
cell = cells[0];
|
|
425
|
+
expect(cell.output).not.toBe(null); // keep old output
|
|
426
|
+
expect(cell).toMatchSnapshot("error response received");
|
|
311
427
|
|
|
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({
|
|
428
|
+
// INTERRUPT RESPONSE
|
|
429
|
+
/////////////////
|
|
430
|
+
// Prepare for run
|
|
431
|
+
actions.prepareForRun({
|
|
1000
432
|
cellId: firstCellId,
|
|
1001
433
|
});
|
|
1002
434
|
cell = cells[0];
|
|
@@ -1007,7 +439,6 @@ describe("cell reducer", () => {
|
|
|
1007
439
|
output: undefined,
|
|
1008
440
|
console: null,
|
|
1009
441
|
status: "queued",
|
|
1010
|
-
stale_inputs: null,
|
|
1011
442
|
timestamp: new Date(40).getTime() as Seconds,
|
|
1012
443
|
});
|
|
1013
444
|
cell = cells[0];
|
|
@@ -1018,62 +449,6 @@ describe("cell reducer", () => {
|
|
|
1018
449
|
output: undefined,
|
|
1019
450
|
console: null,
|
|
1020
451
|
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({
|
|
1055
|
-
cellId: firstCellId,
|
|
1056
|
-
});
|
|
1057
|
-
cell = cells[0];
|
|
1058
|
-
expect(cell.output).not.toBe(null); // keep old output
|
|
1059
|
-
// Queue
|
|
1060
|
-
actions.handleCellMessage({
|
|
1061
|
-
cell_id: firstCellId,
|
|
1062
|
-
output: undefined,
|
|
1063
|
-
console: null,
|
|
1064
|
-
status: "queued",
|
|
1065
|
-
stale_inputs: null,
|
|
1066
|
-
timestamp: new Date(40).getTime() as Seconds,
|
|
1067
|
-
});
|
|
1068
|
-
cell = cells[0];
|
|
1069
|
-
expect(cell.output).not.toBe(null); // keep old output
|
|
1070
|
-
// Running
|
|
1071
|
-
actions.handleCellMessage({
|
|
1072
|
-
cell_id: firstCellId,
|
|
1073
|
-
output: undefined,
|
|
1074
|
-
console: null,
|
|
1075
|
-
status: "running",
|
|
1076
|
-
stale_inputs: null,
|
|
1077
452
|
timestamp: new Date(50).getTime() as Seconds,
|
|
1078
453
|
});
|
|
1079
454
|
cell = cells[0];
|
|
@@ -1089,100 +464,23 @@ describe("cell reducer", () => {
|
|
|
1089
464
|
},
|
|
1090
465
|
console: null,
|
|
1091
466
|
status: "idle",
|
|
1092
|
-
stale_inputs: null,
|
|
1093
467
|
timestamp: new Date(61).getTime() as Seconds,
|
|
1094
468
|
});
|
|
1095
469
|
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
470
|
expect(cell).toMatchSnapshot("interruption response received");
|
|
1102
471
|
});
|
|
1103
472
|
|
|
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
473
|
it("can run a stale cell", () => {
|
|
1168
474
|
// Update code of first cell
|
|
1169
|
-
|
|
1170
|
-
cellId: firstCellId,
|
|
1171
|
-
code: "import marimo as mo",
|
|
1172
|
-
formattingChange: false,
|
|
1173
|
-
});
|
|
475
|
+
editCode(firstCellId, "import marimo as mo");
|
|
1174
476
|
// Add cell
|
|
1175
|
-
|
|
477
|
+
seedCell({
|
|
1176
478
|
cellId: firstCellId,
|
|
1177
479
|
before: false,
|
|
1178
480
|
});
|
|
1179
481
|
const secondCell = cells[1].id;
|
|
1180
482
|
// Update code
|
|
1181
|
-
|
|
1182
|
-
code: "mo.slider()",
|
|
1183
|
-
cellId: secondCell,
|
|
1184
|
-
formattingChange: false,
|
|
1185
|
-
});
|
|
483
|
+
editCode(secondCell, "mo.slider()");
|
|
1186
484
|
|
|
1187
485
|
// Prepare for run
|
|
1188
486
|
actions.prepareForRun({
|
|
@@ -1195,15 +493,9 @@ describe("cell reducer", () => {
|
|
|
1195
493
|
output: undefined,
|
|
1196
494
|
console: null,
|
|
1197
495
|
status: "queued",
|
|
1198
|
-
stale_inputs: null,
|
|
1199
496
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1200
497
|
});
|
|
1201
498
|
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
499
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1208
500
|
|
|
1209
501
|
// Receive stale message
|
|
@@ -1212,105 +504,15 @@ describe("cell reducer", () => {
|
|
|
1212
504
|
output: undefined,
|
|
1213
505
|
console: null,
|
|
1214
506
|
status: undefined,
|
|
1215
|
-
stale_inputs: true,
|
|
1216
507
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1217
508
|
});
|
|
1218
509
|
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
510
|
expect(cell).toMatchSnapshot("stale inputs received");
|
|
1225
511
|
});
|
|
1226
512
|
|
|
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
513
|
it("can run a stopped cell", () => {
|
|
1308
514
|
// Update code of first cell
|
|
1309
|
-
|
|
1310
|
-
cellId: firstCellId,
|
|
1311
|
-
code: "mo.md('This has an ancestor that was stopped')",
|
|
1312
|
-
formattingChange: false,
|
|
1313
|
-
});
|
|
515
|
+
editCode(firstCellId, "mo.md('This has an ancestor that was stopped')");
|
|
1314
516
|
|
|
1315
517
|
// Prepare for run
|
|
1316
518
|
actions.prepareForRun({
|
|
@@ -1323,17 +525,9 @@ describe("cell reducer", () => {
|
|
|
1323
525
|
output: undefined,
|
|
1324
526
|
console: null,
|
|
1325
527
|
status: "queued",
|
|
1326
|
-
stale_inputs: null,
|
|
1327
528
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1328
529
|
});
|
|
1329
530
|
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
531
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1338
532
|
|
|
1339
533
|
// Receive idle message
|
|
@@ -1342,7 +536,6 @@ describe("cell reducer", () => {
|
|
|
1342
536
|
output: undefined,
|
|
1343
537
|
console: null,
|
|
1344
538
|
status: "idle",
|
|
1345
|
-
stale_inputs: null,
|
|
1346
539
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1347
540
|
});
|
|
1348
541
|
cell = cells[0];
|
|
@@ -1365,16 +558,13 @@ describe("cell reducer", () => {
|
|
|
1365
558
|
},
|
|
1366
559
|
console: null,
|
|
1367
560
|
status: "idle",
|
|
1368
|
-
stale_inputs: null,
|
|
1369
561
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1370
562
|
});
|
|
1371
563
|
cell = cells[0];
|
|
1372
|
-
expect(cell.status).toBe("idle");
|
|
1373
564
|
// oxlint-disable-next-line typescript/no-explicit-any no-unsafe-optional-chaining
|
|
1374
565
|
expect((cell.output?.data as any)[0].msg).toBe(
|
|
1375
566
|
"This cell wasn't run because an ancestor was stopped with `mo.stop`: ",
|
|
1376
567
|
);
|
|
1377
|
-
expect(cell.stopped).toBe(true);
|
|
1378
568
|
expect(cell).toMatchSnapshot("ancestor stopped");
|
|
1379
569
|
|
|
1380
570
|
// Receive queued message
|
|
@@ -1383,12 +573,9 @@ describe("cell reducer", () => {
|
|
|
1383
573
|
output: undefined,
|
|
1384
574
|
console: null,
|
|
1385
575
|
status: "queued",
|
|
1386
|
-
stale_inputs: null,
|
|
1387
576
|
timestamp: new Date(30).getTime() as Seconds,
|
|
1388
577
|
});
|
|
1389
578
|
cell = cells[0];
|
|
1390
|
-
expect(cell.status).toBe("queued");
|
|
1391
|
-
expect(cell.stopped).toBe(true);
|
|
1392
579
|
expect(cell).toMatchSnapshot("queued after stop");
|
|
1393
580
|
|
|
1394
581
|
// Receive running message
|
|
@@ -1397,12 +584,9 @@ describe("cell reducer", () => {
|
|
|
1397
584
|
output: undefined,
|
|
1398
585
|
console: null,
|
|
1399
586
|
status: "running",
|
|
1400
|
-
stale_inputs: null,
|
|
1401
587
|
timestamp: new Date(40).getTime() as Seconds,
|
|
1402
588
|
});
|
|
1403
589
|
cell = cells[0];
|
|
1404
|
-
expect(cell.status).toBe("running");
|
|
1405
|
-
expect(cell.stopped).toBe(false);
|
|
1406
590
|
expect(cell.output).toBe(null);
|
|
1407
591
|
expect(cell).toMatchSnapshot("running after stop");
|
|
1408
592
|
});
|
|
@@ -1429,7 +613,6 @@ describe("cell reducer", () => {
|
|
|
1429
613
|
|
|
1430
614
|
// Initial state
|
|
1431
615
|
let cell = cells[0];
|
|
1432
|
-
expect(cell.status).toBe("idle");
|
|
1433
616
|
expect(cell.consoleOutputs).toEqual([]);
|
|
1434
617
|
expect(cell).toMatchSnapshot("initial state");
|
|
1435
618
|
|
|
@@ -1438,7 +621,6 @@ describe("cell reducer", () => {
|
|
|
1438
621
|
cellId: firstCellId,
|
|
1439
622
|
});
|
|
1440
623
|
cell = cells[0];
|
|
1441
|
-
expect(cell.status).toBe("queued");
|
|
1442
624
|
expect(cell.consoleOutputs).toEqual([]);
|
|
1443
625
|
expect(cell).toMatchSnapshot("prepared for run");
|
|
1444
626
|
|
|
@@ -1448,11 +630,9 @@ describe("cell reducer", () => {
|
|
|
1448
630
|
output: undefined,
|
|
1449
631
|
console: null,
|
|
1450
632
|
status: "queued",
|
|
1451
|
-
stale_inputs: null,
|
|
1452
633
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1453
634
|
});
|
|
1454
635
|
cell = cells[0];
|
|
1455
|
-
expect(cell.status).toBe("queued");
|
|
1456
636
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1457
637
|
|
|
1458
638
|
// Receive running messages
|
|
@@ -1461,11 +641,9 @@ describe("cell reducer", () => {
|
|
|
1461
641
|
output: undefined,
|
|
1462
642
|
console: null,
|
|
1463
643
|
status: "running",
|
|
1464
|
-
stale_inputs: null,
|
|
1465
644
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1466
645
|
});
|
|
1467
646
|
cell = cells[0];
|
|
1468
|
-
expect(cell.status).toBe("running");
|
|
1469
647
|
expect(cell).toMatchSnapshot("running message received");
|
|
1470
648
|
|
|
1471
649
|
// Add console
|
|
@@ -1474,16 +652,13 @@ describe("cell reducer", () => {
|
|
|
1474
652
|
output: undefined,
|
|
1475
653
|
console: STDOUT,
|
|
1476
654
|
status: undefined,
|
|
1477
|
-
stale_inputs: null,
|
|
1478
655
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1479
656
|
});
|
|
1480
657
|
cell = cells[0];
|
|
1481
|
-
expect(cell.status).toBe("running");
|
|
1482
658
|
expect(cell).toMatchSnapshot("stdout received");
|
|
1483
659
|
|
|
1484
660
|
cell = cells[0];
|
|
1485
661
|
expect(cell.consoleOutputs[0]).toMatchObject(STDOUT);
|
|
1486
|
-
expect(cell.status).toBe("running");
|
|
1487
662
|
expect(cell).toMatchSnapshot("stdout verified");
|
|
1488
663
|
|
|
1489
664
|
// Ask via stdin
|
|
@@ -1492,13 +667,11 @@ describe("cell reducer", () => {
|
|
|
1492
667
|
output: undefined,
|
|
1493
668
|
console: STD_IN_1,
|
|
1494
669
|
status: undefined,
|
|
1495
|
-
stale_inputs: null,
|
|
1496
670
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1497
671
|
});
|
|
1498
672
|
cell = cells[0];
|
|
1499
673
|
expect(cell.consoleOutputs[0]).toMatchObject(STDOUT);
|
|
1500
674
|
expect(cell.consoleOutputs[1]).toMatchObject(STD_IN_1);
|
|
1501
|
-
expect(cell.status).toBe("running");
|
|
1502
675
|
expect(cell).toMatchSnapshot("stdin requested");
|
|
1503
676
|
|
|
1504
677
|
// Response to stdin
|
|
@@ -1512,7 +685,6 @@ describe("cell reducer", () => {
|
|
|
1512
685
|
...STD_IN_1,
|
|
1513
686
|
response: "Marimo!",
|
|
1514
687
|
});
|
|
1515
|
-
expect(cell.status).toBe("running");
|
|
1516
688
|
expect(cell).toMatchSnapshot("stdin answered");
|
|
1517
689
|
|
|
1518
690
|
// Ask via stdin, again
|
|
@@ -1521,7 +693,6 @@ describe("cell reducer", () => {
|
|
|
1521
693
|
output: undefined,
|
|
1522
694
|
console: STD_IN_2,
|
|
1523
695
|
status: undefined,
|
|
1524
|
-
stale_inputs: null,
|
|
1525
696
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1526
697
|
});
|
|
1527
698
|
cell = cells[0];
|
|
@@ -1530,7 +701,6 @@ describe("cell reducer", () => {
|
|
|
1530
701
|
{ ...STD_IN_1, response: "Marimo!" },
|
|
1531
702
|
STD_IN_2,
|
|
1532
703
|
]);
|
|
1533
|
-
expect(cell.status).toBe("running");
|
|
1534
704
|
expect(cell).toMatchSnapshot("second stdin requested");
|
|
1535
705
|
|
|
1536
706
|
// Interrupt, so we respond with ""
|
|
@@ -1544,11 +714,9 @@ describe("cell reducer", () => {
|
|
|
1544
714
|
},
|
|
1545
715
|
console: null,
|
|
1546
716
|
status: "idle",
|
|
1547
|
-
stale_inputs: null,
|
|
1548
717
|
timestamp: new Date(61).getTime() as Seconds,
|
|
1549
718
|
});
|
|
1550
719
|
cell = cells[0];
|
|
1551
|
-
expect(cell.status).toBe("idle");
|
|
1552
720
|
expect(cell.consoleOutputs).toMatchObject([
|
|
1553
721
|
STDOUT,
|
|
1554
722
|
{ ...STD_IN_1, response: "Marimo!" },
|
|
@@ -1568,7 +736,6 @@ describe("cell reducer", () => {
|
|
|
1568
736
|
output: undefined,
|
|
1569
737
|
console: prompt,
|
|
1570
738
|
status: "running",
|
|
1571
|
-
stale_inputs: null,
|
|
1572
739
|
timestamp: 1 as Seconds,
|
|
1573
740
|
});
|
|
1574
741
|
|
|
@@ -1579,7 +746,9 @@ describe("cell reducer", () => {
|
|
|
1579
746
|
response: secret,
|
|
1580
747
|
});
|
|
1581
748
|
|
|
1582
|
-
expect(cells[0].consoleOutputs).toEqual([
|
|
749
|
+
expect(cells[0].consoleOutputs).toEqual([
|
|
750
|
+
{ ...prompt, id: 1, response: "" },
|
|
751
|
+
]);
|
|
1583
752
|
expect(JSON.stringify(cells[0].consoleOutputs)).not.toContain(secret);
|
|
1584
753
|
});
|
|
1585
754
|
|
|
@@ -1598,7 +767,6 @@ describe("cell reducer", () => {
|
|
|
1598
767
|
output: undefined,
|
|
1599
768
|
console: null,
|
|
1600
769
|
status: "running",
|
|
1601
|
-
stale_inputs: null,
|
|
1602
770
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1603
771
|
});
|
|
1604
772
|
actions.handleCellMessage({
|
|
@@ -1606,7 +774,6 @@ describe("cell reducer", () => {
|
|
|
1606
774
|
output: undefined,
|
|
1607
775
|
console: STDOUT,
|
|
1608
776
|
status: undefined,
|
|
1609
|
-
stale_inputs: null,
|
|
1610
777
|
timestamp: new Date(22).getTime() as Seconds,
|
|
1611
778
|
});
|
|
1612
779
|
|
|
@@ -1640,7 +807,6 @@ describe("cell reducer", () => {
|
|
|
1640
807
|
|
|
1641
808
|
// Initial state
|
|
1642
809
|
let cell = cells[0];
|
|
1643
|
-
expect(cell.status).toBe("idle");
|
|
1644
810
|
expect(cell.consoleOutputs).toEqual([]);
|
|
1645
811
|
expect(cell).toMatchSnapshot("initial state");
|
|
1646
812
|
|
|
@@ -1650,7 +816,6 @@ describe("cell reducer", () => {
|
|
|
1650
816
|
output: undefined,
|
|
1651
817
|
console: [OLD_STDOUT],
|
|
1652
818
|
status: undefined,
|
|
1653
|
-
stale_inputs: null,
|
|
1654
819
|
timestamp: new Date(1).getTime() as Seconds,
|
|
1655
820
|
});
|
|
1656
821
|
|
|
@@ -1659,7 +824,6 @@ describe("cell reducer", () => {
|
|
|
1659
824
|
cellId: firstCellId,
|
|
1660
825
|
});
|
|
1661
826
|
cell = cells[0];
|
|
1662
|
-
expect(cell.status).toBe("queued");
|
|
1663
827
|
expect(cell.consoleOutputs).toMatchObject([OLD_STDOUT]); // Old stays there until it starts running
|
|
1664
828
|
expect(cell).toMatchSnapshot("prepared for run");
|
|
1665
829
|
|
|
@@ -1669,11 +833,9 @@ describe("cell reducer", () => {
|
|
|
1669
833
|
output: undefined,
|
|
1670
834
|
console: null,
|
|
1671
835
|
status: "queued",
|
|
1672
|
-
stale_inputs: null,
|
|
1673
836
|
timestamp: new Date(10).getTime() as Seconds,
|
|
1674
837
|
});
|
|
1675
838
|
cell = cells[0];
|
|
1676
|
-
expect(cell.status).toBe("queued");
|
|
1677
839
|
expect(cell.consoleOutputs).toMatchObject([OLD_STDOUT]); // Old stays there until it starts running
|
|
1678
840
|
expect(cell).toMatchSnapshot("queued message received");
|
|
1679
841
|
|
|
@@ -1683,11 +845,9 @@ describe("cell reducer", () => {
|
|
|
1683
845
|
output: undefined,
|
|
1684
846
|
console: [], // Backend sends an empty array to clearu
|
|
1685
847
|
status: "running",
|
|
1686
|
-
stale_inputs: null,
|
|
1687
848
|
timestamp: new Date(20).getTime() as Seconds,
|
|
1688
849
|
});
|
|
1689
850
|
cell = cells[0];
|
|
1690
|
-
expect(cell.status).toBe("running");
|
|
1691
851
|
expect(cell.consoleOutputs).toMatchObject([]);
|
|
1692
852
|
expect(cell).toMatchSnapshot("console cleared while running");
|
|
1693
853
|
|
|
@@ -1696,611 +856,39 @@ describe("cell reducer", () => {
|
|
|
1696
856
|
cell_id: firstCellId,
|
|
1697
857
|
output: undefined,
|
|
1698
858
|
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);
|
|
859
|
+
status: "idle",
|
|
860
|
+
timestamp: new Date(22).getTime() as Seconds,
|
|
861
|
+
});
|
|
862
|
+
cell = cells[0];
|
|
863
|
+
expect(cell.consoleOutputs).toMatchObject([STDOUT]);
|
|
864
|
+
expect(cell).toMatchSnapshot("console received while idle");
|
|
2262
865
|
});
|
|
2263
866
|
|
|
2264
|
-
it("can
|
|
2265
|
-
actions.
|
|
2266
|
-
|
|
2267
|
-
actions.collapseCell({ cellId: firstCellId });
|
|
867
|
+
it("can fold and unfold all cells", () => {
|
|
868
|
+
actions.foldAll();
|
|
869
|
+
expect(foldAllBulk).toHaveBeenCalled();
|
|
2268
870
|
|
|
2269
|
-
actions.
|
|
2270
|
-
expect(
|
|
2271
|
-
false,
|
|
2272
|
-
);
|
|
871
|
+
actions.unfoldAll();
|
|
872
|
+
expect(unfoldAllBulk).toHaveBeenCalled();
|
|
2273
873
|
});
|
|
2274
874
|
|
|
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");
|
|
875
|
+
it("can clear logs", () => {
|
|
876
|
+
state.cellLogs = [
|
|
877
|
+
{
|
|
878
|
+
level: "stderr",
|
|
879
|
+
message: "log1",
|
|
880
|
+
timestamp: 0,
|
|
881
|
+
source: { type: "cell", cellId: firstCellId },
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
level: "stderr",
|
|
885
|
+
message: "log1",
|
|
886
|
+
timestamp: 0,
|
|
887
|
+
source: { type: "cell", cellId: firstCellId },
|
|
888
|
+
},
|
|
889
|
+
];
|
|
890
|
+
actions.clearLogs();
|
|
891
|
+
expect(state.cellLogs).toEqual([]);
|
|
2304
892
|
});
|
|
2305
893
|
|
|
2306
894
|
it("can handle multiple console outputs", () => {
|
|
@@ -2322,7 +910,6 @@ describe("cell reducer", () => {
|
|
|
2322
910
|
output: undefined,
|
|
2323
911
|
console: [STDOUT1, STDOUT2],
|
|
2324
912
|
status: "running",
|
|
2325
|
-
stale_inputs: null,
|
|
2326
913
|
timestamp: new Date(20).getTime() as Seconds,
|
|
2327
914
|
});
|
|
2328
915
|
|
|
@@ -2339,407 +926,6 @@ describe("cell reducer", () => {
|
|
|
2339
926
|
`);
|
|
2340
927
|
});
|
|
2341
928
|
|
|
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
929
|
it("can clear output of a single cell", () => {
|
|
2744
930
|
// Set up initial state with output
|
|
2745
931
|
actions.handleCellMessage({
|
|
@@ -2757,7 +943,6 @@ describe("cell reducer", () => {
|
|
|
2757
943
|
timestamp: 0,
|
|
2758
944
|
},
|
|
2759
945
|
status: "idle",
|
|
2760
|
-
stale_inputs: null,
|
|
2761
946
|
timestamp: new Date(33).getTime() as Seconds,
|
|
2762
947
|
});
|
|
2763
948
|
|
|
@@ -2792,7 +977,6 @@ describe("cell reducer", () => {
|
|
|
2792
977
|
timestamp: 0,
|
|
2793
978
|
},
|
|
2794
979
|
status: "idle",
|
|
2795
|
-
stale_inputs: null,
|
|
2796
980
|
timestamp: new Date(33).getTime() as Seconds,
|
|
2797
981
|
});
|
|
2798
982
|
|
|
@@ -2806,7 +990,6 @@ describe("cell reducer", () => {
|
|
|
2806
990
|
timestamp: 0,
|
|
2807
991
|
},
|
|
2808
992
|
status: "idle",
|
|
2809
|
-
stale_inputs: null,
|
|
2810
993
|
timestamp: new Date(34).getTime() as Seconds,
|
|
2811
994
|
});
|
|
2812
995
|
|
|
@@ -2828,8 +1011,8 @@ describe("cell reducer", () => {
|
|
|
2828
1011
|
|
|
2829
1012
|
it("can clear output of all cells", () => {
|
|
2830
1013
|
// Create multiple cells with output
|
|
2831
|
-
|
|
2832
|
-
const secondCellId = state.cellIds
|
|
1014
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1015
|
+
const secondCellId = state.cellIds[1];
|
|
2833
1016
|
|
|
2834
1017
|
// Add output to both cells
|
|
2835
1018
|
const outputMessage = {
|
|
@@ -2846,7 +1029,6 @@ describe("cell reducer", () => {
|
|
|
2846
1029
|
timestamp: 0,
|
|
2847
1030
|
},
|
|
2848
1031
|
status: "idle",
|
|
2849
|
-
stale_inputs: null,
|
|
2850
1032
|
timestamp: new Date(33).getTime() as Seconds,
|
|
2851
1033
|
} as const;
|
|
2852
1034
|
|
|
@@ -2854,142 +1036,30 @@ describe("cell reducer", () => {
|
|
|
2854
1036
|
...outputMessage,
|
|
2855
1037
|
cell_id: firstCellId,
|
|
2856
1038
|
});
|
|
2857
|
-
actions.handleCellMessage({
|
|
2858
|
-
...outputMessage,
|
|
2859
|
-
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" });
|
|
1039
|
+
actions.handleCellMessage({
|
|
1040
|
+
...outputMessage,
|
|
1041
|
+
cell_id: secondCellId,
|
|
1042
|
+
});
|
|
2975
1043
|
|
|
2976
|
-
//
|
|
2977
|
-
|
|
1044
|
+
// Verify initial state has output
|
|
1045
|
+
expect(state.cellRuntime[firstCellId].output).not.toBeNull();
|
|
1046
|
+
expect(state.cellRuntime[firstCellId].consoleOutputs.length).toBe(1);
|
|
1047
|
+
expect(state.cellRuntime[secondCellId].output).not.toBeNull();
|
|
1048
|
+
expect(state.cellRuntime[secondCellId].consoleOutputs.length).toBe(1);
|
|
2978
1049
|
|
|
2979
|
-
//
|
|
2980
|
-
actions.
|
|
1050
|
+
// Clear all outputs
|
|
1051
|
+
actions.clearAllCellOutputs();
|
|
2981
1052
|
|
|
2982
|
-
//
|
|
2983
|
-
expect(state.
|
|
2984
|
-
expect(state.
|
|
2985
|
-
expect(state.
|
|
2986
|
-
expect(state.
|
|
2987
|
-
expect(state.cellIds.inOrderIds).toContain(SETUP_CELL_ID);
|
|
1053
|
+
// Verify all outputs are cleared
|
|
1054
|
+
expect(state.cellRuntime[firstCellId].output).toBeNull();
|
|
1055
|
+
expect(state.cellRuntime[firstCellId].consoleOutputs).toEqual([]);
|
|
1056
|
+
expect(state.cellRuntime[secondCellId].output).toBeNull();
|
|
1057
|
+
expect(state.cellRuntime[secondCellId].consoleOutputs).toEqual([]);
|
|
2988
1058
|
});
|
|
2989
1059
|
|
|
2990
1060
|
it("can clear all outputs", () => {
|
|
2991
1061
|
// Add a cell and give it output
|
|
2992
|
-
|
|
1062
|
+
seedCell({
|
|
2993
1063
|
cellId: firstCellId,
|
|
2994
1064
|
before: false,
|
|
2995
1065
|
});
|
|
@@ -3017,522 +1087,13 @@ describe("cell reducer", () => {
|
|
|
3017
1087
|
expect(state.cellRuntime[cell2Id].output).toBeNull();
|
|
3018
1088
|
});
|
|
3019
1089
|
|
|
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
1090
|
describe("releaseCellAtoms", () => {
|
|
3530
1091
|
it("atom families cache atoms until explicitly removed", () => {
|
|
3531
1092
|
const { cellDataAtom, cellRuntimeAtom, cellHandleAtom } =
|
|
3532
1093
|
exportedForTesting;
|
|
3533
1094
|
|
|
3534
|
-
|
|
3535
|
-
const newCellId = state.cellIds
|
|
1095
|
+
seedCell({ cellId: firstCellId, before: false });
|
|
1096
|
+
const newCellId = state.cellIds[1];
|
|
3536
1097
|
|
|
3537
1098
|
const dataAtom1 = cellDataAtom(newCellId);
|
|
3538
1099
|
const runtimeAtom1 = cellRuntimeAtom(newCellId);
|
|
@@ -3547,116 +1108,15 @@ describe("cell reducer", () => {
|
|
|
3547
1108
|
expect(runtimeAtom2).toBe(runtimeAtom1);
|
|
3548
1109
|
expect(handleAtom2).toBe(handleAtom1);
|
|
3549
1110
|
});
|
|
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
1111
|
});
|
|
1112
|
+
it("withdraws the submission of a cell that leaves the document", () => {
|
|
1113
|
+
MockExecutions.seed(store, []);
|
|
1114
|
+
submitCells(store, [firstCellId]);
|
|
1115
|
+
expect(store.get(notebookQueuedOrRunningCountAtom)).toBe(1);
|
|
3641
1116
|
|
|
3642
|
-
|
|
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
|
-
};
|
|
1117
|
+
actions.reconcileDocument({ order: [], cells: new Map() });
|
|
3656
1118
|
|
|
3657
|
-
expect(
|
|
3658
|
-
false,
|
|
3659
|
-
);
|
|
1119
|
+
expect(store.get(notebookQueuedOrRunningCountAtom)).toBe(0);
|
|
3660
1120
|
});
|
|
3661
1121
|
});
|
|
3662
1122
|
|
|
@@ -3839,11 +1299,11 @@ describe("createTracebackInfoAtom", () => {
|
|
|
3839
1299
|
data: [{ type: "syntax", msg: "Syntax error", lineno: 1 }],
|
|
3840
1300
|
mimetype: "application/vnd.marimo+error",
|
|
3841
1301
|
},
|
|
3842
|
-
status: "queued",
|
|
3843
1302
|
},
|
|
3844
1303
|
},
|
|
3845
1304
|
}),
|
|
3846
1305
|
);
|
|
1306
|
+
MockExecutions.seed(store, [MockExecutions.queued(cellId("cell1"))]);
|
|
3847
1307
|
|
|
3848
1308
|
const tracebackAtom = exportedForTesting.createTracebackInfoAtom(
|
|
3849
1309
|
cellId("cell1"),
|
|
@@ -3871,11 +1331,11 @@ describe("createTracebackInfoAtom", () => {
|
|
|
3871
1331
|
data: [{ type: "syntax", msg: "Syntax error", lineno: 1 }],
|
|
3872
1332
|
mimetype: "application/vnd.marimo+error",
|
|
3873
1333
|
},
|
|
3874
|
-
status: "running",
|
|
3875
1334
|
},
|
|
3876
1335
|
},
|
|
3877
1336
|
}),
|
|
3878
1337
|
);
|
|
1338
|
+
MockExecutions.seed(store, [MockExecutions.running(cellId("cell1"))]);
|
|
3879
1339
|
|
|
3880
1340
|
const tracebackAtom = exportedForTesting.createTracebackInfoAtom(
|
|
3881
1341
|
cellId("cell1"),
|
|
@@ -3886,31 +1346,9 @@ describe("createTracebackInfoAtom", () => {
|
|
|
3886
1346
|
});
|
|
3887
1347
|
});
|
|
3888
1348
|
|
|
3889
|
-
describe("
|
|
1349
|
+
describe("kernel-ready", () => {
|
|
3890
1350
|
const CELL_A = cellId("A");
|
|
3891
1351
|
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
1352
|
|
|
3915
1353
|
const hydratedState = () =>
|
|
3916
1354
|
MockNotebook.notebookState({
|
|
@@ -3940,44 +1378,74 @@ describe("setCells snapshot preservation", () => {
|
|
|
3940
1378
|
},
|
|
3941
1379
|
});
|
|
3942
1380
|
|
|
3943
|
-
|
|
3944
|
-
const { isWasm } = await import("@/core/wasm/utils");
|
|
3945
|
-
vi.mocked(isWasm).mockReturnValue(true);
|
|
3946
|
-
});
|
|
3947
|
-
|
|
3948
|
-
it("preserves hydrated output in WASM", () => {
|
|
1381
|
+
it("resetCellRuntimes starts every cell's runtime over", () => {
|
|
3949
1382
|
const next = exportedForTesting.reducer(hydratedState(), {
|
|
3950
|
-
type: "
|
|
3951
|
-
payload:
|
|
1383
|
+
type: "resetCellRuntimes",
|
|
1384
|
+
payload: undefined,
|
|
3952
1385
|
});
|
|
3953
1386
|
|
|
3954
|
-
expect(next.cellRuntime[CELL_A].output).
|
|
3955
|
-
|
|
1387
|
+
expect(next.cellRuntime[CELL_A].output).toBeNull();
|
|
1388
|
+
expect(next.cellRuntime[CELL_B].consoleOutputs).toEqual([]);
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1391
|
+
it("resetCellRuntimes starts the scratch cell over too", () => {
|
|
1392
|
+
const state = MockNotebook.notebookState({
|
|
1393
|
+
cellData: { [CELL_A]: { id: CELL_A, code: "1" } },
|
|
1394
|
+
cellRuntime: {
|
|
1395
|
+
[SCRATCH_CELL_ID]: {
|
|
1396
|
+
output: {
|
|
1397
|
+
channel: "output",
|
|
1398
|
+
mimetype: "text/plain",
|
|
1399
|
+
data: "scratch",
|
|
1400
|
+
timestamp: 0,
|
|
1401
|
+
},
|
|
1402
|
+
},
|
|
1403
|
+
},
|
|
3956
1404
|
});
|
|
1405
|
+
const next = exportedForTesting.reducer(state, {
|
|
1406
|
+
type: "resetCellRuntimes",
|
|
1407
|
+
payload: undefined,
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
expect(next.cellRuntime[SCRATCH_CELL_ID].output).toBeNull();
|
|
3957
1411
|
});
|
|
3958
1412
|
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
1413
|
+
describe("resetCellRuntimes in WASM", () => {
|
|
1414
|
+
beforeEach(async () => {
|
|
1415
|
+
const { isWasm } = await import("@/core/wasm/utils");
|
|
1416
|
+
vi.mocked(isWasm).mockReturnValue(true);
|
|
3963
1417
|
});
|
|
3964
1418
|
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
1419
|
+
afterEach(async () => {
|
|
1420
|
+
const { isWasm } = await import("@/core/wasm/utils");
|
|
1421
|
+
vi.mocked(isWasm).mockReturnValue(false);
|
|
3968
1422
|
});
|
|
3969
|
-
});
|
|
3970
1423
|
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
1424
|
+
it("keeps hydrated outputs and console", () => {
|
|
1425
|
+
const next = exportedForTesting.reducer(hydratedState(), {
|
|
1426
|
+
type: "resetCellRuntimes",
|
|
1427
|
+
payload: undefined,
|
|
1428
|
+
});
|
|
1429
|
+
|
|
1430
|
+
expect(next.cellRuntime[CELL_A].output).toMatchObject({
|
|
1431
|
+
data: "hydrated-A",
|
|
1432
|
+
});
|
|
1433
|
+
expect(next.cellRuntime[CELL_B].consoleOutputs[0]).toMatchObject({
|
|
1434
|
+
data: "hydrated-B-stdout",
|
|
1435
|
+
});
|
|
3976
1436
|
});
|
|
3977
1437
|
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
1438
|
+
it("starts cells with no prior runtime over", () => {
|
|
1439
|
+
const state = MockNotebook.notebookState({
|
|
1440
|
+
cellData: { [CELL_A]: { id: CELL_A, code: "1" } },
|
|
1441
|
+
});
|
|
1442
|
+
const next = exportedForTesting.reducer(state, {
|
|
1443
|
+
type: "resetCellRuntimes",
|
|
1444
|
+
payload: undefined,
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1447
|
+
expect(next.cellRuntime[CELL_A].output).toBeNull();
|
|
1448
|
+
expect(next.cellRuntime[CELL_A].consoleOutputs).toEqual([]);
|
|
1449
|
+
});
|
|
3982
1450
|
});
|
|
3983
1451
|
});
|