@marimo-team/islands 0.24.3-dev9 → 0.25.1-dev1
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-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
- package/dist/ErrorBoundary-pXXIvlr3.js +200 -0
- package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-Dlm5aWnH.js} +4 -4
- package/dist/{Plot-C-9MQeGP.js → Plot-CTyjbQDT.js} +21032 -20666
- package/dist/_baseMerge-BiGRwuqv.js +165 -0
- package/dist/{abnfDiagram-N423BO3Z-CQKwzX8t.js → abnfDiagram-VCTEODGH-CpN0FRda.js} +17 -18
- package/dist/{any-language-editor-DmQ7dyCx.js → any-language-editor-CycIVIeP.js} +17 -17
- package/dist/arc-7ra3iNdN.js +81 -0
- package/dist/architecture-7GRP2DOG-BWLylgiA.js +3 -0
- package/dist/{architectureDiagram-T3A2C74G-CncrDpfa.js → architectureDiagram-5GKGNRK7-DDyj5SRB.js} +25 -25
- package/dist/assets/__vite-browser-external-C9iR87Zl.js +1 -0
- package/dist/assets/worker-D7hWi02M.js +109 -0
- package/dist/blockDiagram-I7D4REHJ-BbXEXJRu.js +1922 -0
- package/dist/{button-CKBkqR9J.js → button-DdXAm8iz.js} +5 -5
- package/dist/{c4Diagram-5PPSVZJV-DarUk3Yq.js → c4Diagram-7LVT6UL2-DcLsbQmR.js} +696 -668
- package/dist/{capabilities-CMBBJTcc.js → capabilities-B3ce_GNu.js} +1 -1
- package/dist/{html-to-image-BtFMe_Nq.js → cells-DYIkSxs6.js} +6757 -10137
- package/dist/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
- package/dist/chat-ui-BXj3uYjy.js +5786 -0
- package/dist/{check-CHig47QV.js → check-B7cIK6gb.js} +1 -1
- package/dist/{chunk-2Q5K7J3B-BMuJl2jB.js → chunk-2Q5K7J3B-BMkUkeuy.js} +2 -2
- package/dist/chunk-4HAMMTFA-D2qv8E0X.js +4188 -0
- package/dist/{chunk-5VM5RSS4-Bcq0ftdy.js → chunk-5VM5RSS4-DKsmPCL6.js} +2 -2
- package/dist/{chunk-NSK5VX7P-CDTMcJB0.js → chunk-75Z2AOVW-5_HsvXwr.js} +23 -23
- package/dist/{chunk-I66GZJ75-BqyTCAPf.js → chunk-DU6HZSFF-BUgAHvnM.js} +21 -4
- package/dist/{chunk-2GRJ4B5K-DgO8Qudq.js → chunk-F27PBJKO-DHmYWZXr.js} +4 -4
- package/dist/{chunk-KEIR6QF5-C4KX3XYh.js → chunk-FOHPRMQF-BpYR8RqP.js} +4 -4
- package/dist/{chunk-WRU74C26-BpWsbiDK.js → chunk-GMAD6QVW-Czynz8aA.js} +486 -258
- package/dist/chunk-GVQU2GXP-yQEdulRS.js +37 -0
- package/dist/{chunk-5RXB4S5H-tLNUVDdO.js → chunk-IMKFNOWR-BfwTebD0.js} +11 -11
- package/dist/{chunk-JWPE2WC7-BJwjGUnF.js → chunk-JWPE2WC7-DJvv1t8U.js} +2 -2
- package/dist/chunk-L3NEJ4N5-DwRWnDDK.js +245 -0
- package/dist/{chunk-7Z6QIM7H-Dc18hFxH.js → chunk-OSK3NFVY-BBKU_Ign.js} +222 -144
- package/dist/{chunk-W5SLKNZC-DLnvpEtV.js → chunk-P2QGCYS3-C0iGU29N.js} +20 -20
- package/dist/{chunk-KBJHAD2P-BuqWqkcW.js → chunk-POPQ4Y6H-BCbS3Ozc.js} +4 -4
- package/dist/{chunk-4I5QYGJK-DpytHuZQ.js → chunk-PWAF6VOD-CTFCL0jI.js} +4 -4
- package/dist/{chunk-JQJVKLGR-CgqCwe8E.js → chunk-SHT3W25Y-BspJEJ5H.js} +109 -63
- package/dist/{chunk-6Q2QTUOP-DmTcEBMn.js → chunk-SVP7TREG-DX3rFNTe.js} +5 -5
- package/dist/{chunk-GF5L2VYU-B0wgCQgS.js → chunk-TICWLB2K-fVF7Uujg.js} +13 -13
- package/dist/{chunk-XXDRQBXY-D73H4IN0.js → chunk-XXDRQBXY-Dnl5VBqG.js} +3 -3
- package/dist/{chunk-Y2CYZVJY-DoegUj_e.js → chunk-Y2CYZVJY-DKKS1VyV.js} +1 -1
- package/dist/{chunk-5FQGJX7Z-B85XCPv6.js → chunk-YOKDWASO-DrWbKnxA.js} +6925 -5460
- package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +30 -0
- package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +30 -0
- package/dist/code-visibility-BC_yF09p.js +138 -0
- package/dist/{common-Cv-4hMa0.js → common-Dv227ygK.js} +8838 -12645
- package/dist/{compiler-runtime-CAH9RLw2.js → compiler-runtime-Cj8ZWiNS.js} +2 -2
- package/dist/copy-icon-CLdENY__.js +190 -0
- package/dist/{cose-bilkent-JH36ORCC-FUWHkXFX.js → cose-bilkent-JH36ORCC-_LyRKVqm.js} +2 -2
- package/dist/cubic-OaEBhQPK.js +1404 -0
- package/dist/cynefin-OW5HDTMX-obq-i80l.js +3 -0
- package/dist/{cynefinDiagram-MW4NZA55-BXSFK93J.js → cynefinDiagram-5FMLGOSQ-CFQrqzSX.js} +10 -10
- package/dist/{dagre-CGyalH38.js → dagre-BGSfXNEb.js} +678 -537
- package/dist/dagre-GXQ25YYZ-xHNAUTyG.js +425 -0
- package/dist/{data-grid-overlay-editor-DZM4BAaI.js → data-grid-overlay-editor-B-I2K7z3.js} +8 -9
- package/dist/{data-grid-types-BnZwWG8z.js → data-grid-types-BucVmDDp.js} +1 -1
- package/dist/{defaultLocale-DKaU_opG.js → defaultLocale-JI_lnoCe.js} +1 -1
- package/dist/{diagram-7IWD3JNH-BjfzDNvj.js → diagram-S7CK7UJ4-Bt1rPbAx.js} +40 -39
- package/dist/{diagram-UB23O5K3-DDg-7wLA.js → diagram-UQ7AKVKN-D1sq5FoZ.js} +10 -10
- package/dist/{diagram-B4RE2ZJO-CKccR9eE.js → diagram-VSXAHHWV-BKpmG23x.js} +10 -10
- package/dist/{diagram-Q27KOJAE-Zhz01ss7.js → diagram-VX7I27RA-BMwGFVD6.js} +21 -21
- package/dist/{diagram-LBJQPF4R-CJ-bOruh.js → diagram-Z3DM3KII--KLDR9Pl.js} +10 -10
- package/dist/dialog-CgNq6y9-.js +94 -0
- package/dist/{dist-dAqZAPcF.js → dist-1HDa70oE.js} +3 -3
- package/dist/{dist-Re9sOPOx.js → dist-9x1ZRe-e.js} +2 -2
- package/dist/{dist-DEeLqRlU.js → dist-B1vYLK28.js} +1 -1
- package/dist/{dist-C5Bn52W4.js → dist-B8D7McG3.js} +3 -3
- package/dist/{dist-_XvgytiS.js → dist-BHCHt1NI.js} +1 -1
- package/dist/{dist-CRjAdnqF.js → dist-BRxfaJgs.js} +3 -3
- package/dist/{dist-Byj2bV8o.js → dist-BVGtK7Ht.js} +1 -1
- package/dist/{dist-BIN5LKyE.js → dist-BaHjhkpZ.js} +2 -2
- package/dist/{dist-DVFbIwc5.js → dist-BtKIs9N-.js} +1 -1
- package/dist/{dist-BrQGcfQ9.js → dist-C2KzV-vf.js} +2 -2
- package/dist/{dist-DJFiGP2k.js → dist-C2wDlYdD.js} +2 -2
- package/dist/{dist-BVRM2y1P.js → dist-C8xMLVYi.js} +2 -2
- package/dist/dist-CMh_W4y4.js +538 -0
- package/dist/{extends-BPB6_lTK.js → dist-CO1AwwG_.js} +516 -561
- package/dist/{dist-BzN60Z2s.js → dist-CPGxfVGX.js} +1 -1
- package/dist/{dist-C7v-9nUK.js → dist-Cm3iAFMD.js} +3 -3
- package/dist/{dist-CGAxEiaM.js → dist-Cs2FijYk.js} +2 -2
- package/dist/{dist-hXd65f0_.js → dist-D1PpnuZB.js} +1 -1
- package/dist/{dist-VdvbxG72.js → dist-DHOTQar0.js} +1 -1
- package/dist/{dist-DcgzXCfy.js → dist-DPcEtqmG.js} +2 -2
- package/dist/{dist-D4Z_qdP4.js → dist-Df0wKI0F.js} +1 -1
- package/dist/{dist-qhLI-SHd.js → dist-DszxuxS1.js} +2 -2
- package/dist/{dist-BEmkrGoQ.js → dist-Kxgjxakw.js} +1 -1
- package/dist/{dist-BbSMhhD2.js → dist-KzZ7WELx.js} +2 -2
- package/dist/{dist-jWUab2d1.js → dist-lA1Cttkb.js} +1 -1
- package/dist/dropdown-menu-CZgjYSAh.js +4502 -0
- package/dist/{ebnfDiagram-BXEA7PRR-Dm75pCAS.js → ebnfDiagram-PWID7BFC-WnG4cvSQ.js} +17 -18
- package/dist/{erDiagram-JOGREHBK-rVDG3VSQ.js → erDiagram-RLTQ6QDP-DhzKiYHc.js} +1037 -798
- package/dist/error-banner-B94dcDmP.js +391 -0
- package/dist/error-entries-C0NsUqXl.js +56 -0
- package/dist/{esm-CR1nhb1c.js → esm-BElI3qKH.js} +22 -22
- package/dist/{esm-C1d0g6Bv.js → esm-G4Fhsgng.js} +51 -37
- package/dist/{esm-CesmlDrs.js → esm-h8f7-1CJ.js} +423 -423
- package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +3 -0
- package/dist/feedback-button-D2hUXe09.js +380 -0
- package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +16 -0
- package/dist/{formats-CslNOKy0.js → formats-BR5iGb4s.js} +8 -8
- package/dist/{ganttDiagram-PKOTCBZU-9D-LXF6P.js → ganttDiagram-EL5Y4UJY-DbzEBLbl.js} +15 -15
- package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +3 -0
- package/dist/{gitGraphDiagram-DS77QQ5N-BfpsXTLf.js → gitGraphDiagram-WWUBYQGX-BMf0iKi1.js} +10 -10
- package/dist/{glide-data-editor-sPZ8fUFn.js → glide-data-editor-B851uguN.js} +2143 -1910
- package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
- package/dist/globals-CmijFoIU.js +19 -0
- package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
- package/dist/html-to-image-CeYYvQNb.js +3272 -0
- package/dist/info-A6RAGUB7-DKoayiHY.js +3 -0
- package/dist/{infoDiagram-6WML65LV-DqCTXHVy.js → infoDiagram-27XIBGKW-BagtCX_5.js} +7 -7
- package/dist/{ishikawaDiagram-WSZJBQD7-BCUYmZ1v.js → ishikawaDiagram-5VMMS53U-DByDehYy.js} +8 -8
- package/dist/{journeyDiagram-NVQOT4AX-BXB6M4zN.js → journeyDiagram-3NMN7TZE-D2LcKDUO.js} +8 -8
- package/dist/{jsx-runtime-CpoKNRgu.js → jsx-runtime-DgDPJV9S.js} +1 -1
- package/dist/{kanban-definition-27J2QSJJ-CGRhrDUX.js → kanban-definition-UXKFOSKX-BxwkbBI_.js} +29 -29
- package/dist/katex-DFBiSucW.js +21840 -0
- package/dist/{label-lwzzBHUW.js → label-BJ49YTvk.js} +6 -6
- package/dist/{linear-D5r_1YqD.js → linear-Cnaq3Tfb.js} +4 -4
- package/dist/{loader-VZ__bv4g.js → loader-D2W4oM-3.js} +15 -15
- package/dist/main.js +8113 -13475
- package/dist/mermaid-DPNuhemn.js +3084 -0
- package/dist/mermaid-HWGCJPDP-DYCzSILp.js +2 -0
- package/dist/mermaid-parser.core-DxuSfYwJ.js +638 -0
- package/dist/{mhchem-BjwrxcV-.js → mhchem-DWCF06w9.js} +1 -1
- package/dist/{micromark-factory-space-DruVGzeG.js → micromark-factory-space-DGxAzmw8.js} +2 -2
- package/dist/{mindmap-definition-FAOFIHXS-C9gRhzZq.js → mindmap-definition-YA3MSWOX-Cgvojw3y.js} +17 -17
- package/dist/{node-sql-parser-DesT1xNw.js → node-sql-parser-BiZOJ-FS.js} +0 -3
- package/dist/{number-overlay-editor-De2CabLL.js → number-overlay-editor-BtdoxWiD.js} +5 -5
- package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +23 -0
- package/dist/packet-AYTQ26CC-Yw7ajchJ.js +3 -0
- package/dist/{pegDiagram-VL7TDLO6-Df9IUjMD.js → pegDiagram-XKGWAZYB-DahHhYyN.js} +19 -20
- package/dist/{pick-SnHlmIBN.js → pick-CJeoxYOS.js} +1 -1
- package/dist/pie-WAS4IAKB-BKdKOAkL.js +3 -0
- package/dist/{pieDiagram-7S7Q4E2Y-BmRzQ8ZP.js → pieDiagram-E7YTZNPT-CCtX0oCK.js} +29 -31
- package/dist/{process-output-CPy0YKUe.js → process-output-BCTjlyuH.js} +7 -6
- package/dist/purify.es-DgKyQviY.js +805 -0
- package/dist/{quadrantDiagram-CIZ2JOQS-wFBvWcxS.js → quadrantDiagram-AXDQQJYC-DftINo6g.js} +5 -5
- package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +3 -0
- package/dist/railroad-74A4TZTK-DQvPSdo5.js +3 -0
- package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +3 -0
- package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +3 -0
- package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +3 -0
- package/dist/{railroadDiagram-AXF67PYL-DxbIatiN.js → railroadDiagram-O6MQD6OU-Du5NsPUb.js} +17 -18
- package/dist/{react-dom-C94wmq5w.js → react-dom-BUgJ-ab_.js} +3 -3
- package/dist/{react-DMWcHin-.js → react-ofJbxM4x.js} +2 -2
- package/dist/{react-vega-DSD5aT7_.js → react-vega-5AcMW8gG.js} +10012 -9369
- package/dist/{requirementDiagram-LRYGKXZP-X_x-Y713.js → requirementDiagram-BXWQKSXE-0pmmxL6_.js} +20 -19
- package/dist/{reveal-component-CVsYlb9J.js → reveal-component-DQq7NUGJ.js} +1303 -1237
- package/dist/{sankeyDiagram-W5VNT64P-BYJALbbm.js → sankeyDiagram-P5KCCOFB-CDKR5TJH.js} +4 -4
- package/dist/{select-3qHpFKF9.js → select-C6plhmZr.js} +317 -562
- package/dist/{sequenceDiagram-SI44F4Z6-BiPBe3Sv.js → sequenceDiagram-WJ2MYXX4-DB-ChWwU.js} +11 -11
- package/dist/{sizeCapture-X5ZJPWSS-BKLDeh5H.js → sizeCapture-INFHLROL-Dx5SpkQF.js} +2 -2
- package/dist/{spec-CutWdqo3.js → spec-CAYwFeV6.js} +4 -4
- package/dist/{src-C31ngt98.js → src-CA_m4ONl.js} +298 -303
- package/dist/{stateDiagram-OKZ733FA-B7QyNBxH.js → stateDiagram-D77RDMKH-orN6AwMx.js} +19 -20
- package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +30 -0
- package/dist/style.css +2 -2
- package/dist/{swimlanes-SLNWSIFB-B4f8VP3b.js → swimlanes-42K2YHIH-BkSDcqDT.js} +1501 -1591
- package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +30 -0
- package/dist/{swiper-component-C90YjhaV.js → swiper-component-IOUowglM.js} +39 -26
- package/dist/{time-aWGfjN8x.js → time-BieKwdYS.js} +42 -42
- package/dist/{timeline-definition-Z64GVDOM-Dacq_5lr.js → timeline-definition-24CTP7MA-BuqJUIRZ.js} +7 -7
- package/dist/{toDate-CpXBeDq0.js → toDate-WXg1yLcI.js} +7 -7
- package/dist/toast-DvY70eFX.js +1834 -0
- package/dist/tooltip-qB8NlSqV.js +1742 -0
- package/dist/treeView-Q6P3EWNA-DuRV97YF.js +3 -0
- package/dist/treemap-WGGIJYW6-AsLq-uwC.js +3 -0
- package/dist/use-restore-focus-D5D9xEjZ.js +5946 -0
- package/dist/{use-vega-container-remeasure-DUW4tRxq.js → use-vega-container-remeasure-4DwJbPWu.js} +2 -2
- package/dist/{useAsyncData-CH6-CgJF.js → useAsyncData-BD6AStMt.js} +3 -3
- package/dist/{useDateFormatter-Cp9Jdxls.js → useDateFormatter-BRTPsUK7.js} +8 -8
- package/dist/{useDeepCompareMemoize-JC87C_jO.js → useDeepCompareMemoize-D_HNdyvI.js} +2 -2
- package/dist/{useIframeCapabilities-De3C-9b4.js → useIframeCapabilities-CVtNkI3Y.js} +2 -2
- package/dist/{useLifecycle-B4RGlyf0.js → useLifecycle-DPgiiwwU.js} +6 -6
- package/dist/useNumberFormatter-BfDpa21j.js +251 -0
- package/dist/useTheme-DzXmYZ5V.js +904 -0
- package/dist/{vega-component-ovBXgp91.js → vega-component-D0QXopU8.js} +34 -34
- package/dist/{vega-embed-container-TJ5z5dZw.js → vega-embed-container-CbnTccZi.js} +6 -6
- package/dist/vega-loader.browser-D95WfUcj.js +1139 -0
- package/dist/{vennDiagram-T6HMQDX7-D-Rcq3Iu.js → vennDiagram-4TSXK5OY-CTUlJ2PK.js} +9 -9
- package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +3 -0
- package/dist/{wardleyDiagram-T6FBY63Y-Z-Og7_Wd.js → wardleyDiagram-VM6X3IG4-3evLUb0M.js} +10 -10
- package/dist/{xychartDiagram-ELKLHX3M-BDJ2dITA.js → xychartDiagram-S5SC5T6Z-DL2E3K8-.js} +248 -139
- package/package.json +54 -57
- package/src/__mocks__/notebook.ts +1 -0
- package/src/__mocks__/requests.ts +7 -0
- package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
- package/src/__tests__/fixtures/pair-preview.ts +19 -0
- package/src/__tests__/mount.test.ts +18 -0
- package/src/components/app-config/optional-features.tsx +6 -0
- package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +394 -0
- package/src/components/chat/acp/__tests__/agent-panel.test.tsx +272 -0
- package/src/components/chat/acp/__tests__/state.test.ts +2 -2
- package/src/components/chat/acp/agent-panel.tsx +115 -74
- package/src/components/chat/acp/state.ts +1 -1
- package/src/components/data-table/__tests__/filters.test.ts +21 -21
- package/src/components/data-table/charts/__tests__/spec.test.ts +5 -10
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
- package/src/components/data-table/column-summary/chart-spec-model.tsx +1 -1
- package/src/components/data-table/columns.tsx +64 -67
- package/src/components/editor/RecoveryButton.tsx +1 -0
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +115 -0
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +218 -0
- package/src/components/editor/actions/pair-with-agent-commands.ts +46 -9
- package/src/components/editor/actions/pair-with-agent-modal.tsx +49 -23
- package/src/components/editor/ai/add-cell-with-ai.tsx +1 -0
- package/src/components/editor/ai/ai-completion-editor.tsx +3 -1
- package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +186 -0
- package/src/components/editor/alerts/__tests__/startup-progress.test.tsx +185 -0
- package/src/components/editor/alerts/connecting-alert.tsx +1 -66
- package/src/components/editor/alerts/connection-notice.tsx +186 -0
- package/src/components/editor/alerts/startup-output.tsx +173 -0
- package/src/components/editor/alerts/startup-progress.tsx +204 -0
- package/src/components/editor/app-container.tsx +9 -3
- package/src/components/editor/boundary/ErrorBoundary.tsx +38 -16
- package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +311 -0
- package/src/components/editor/cell/__tests__/toolbar.test.tsx +73 -0
- package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +50 -0
- package/src/components/editor/cell/code/cell-editor.tsx +41 -42
- package/src/components/editor/cell/toolbar.tsx +11 -0
- package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +94 -0
- package/src/components/editor/chrome/components/feedback-button.tsx +63 -42
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +164 -8
- package/src/components/editor/chrome/panels/__tests__/sandbox-details.test.tsx +358 -0
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +168 -0
- package/src/components/editor/chrome/panels/packages-panel.tsx +113 -175
- package/src/components/editor/chrome/panels/sandbox-controller.tsx +106 -0
- package/src/components/editor/chrome/panels/sandbox-details-state.ts +38 -0
- package/src/components/editor/chrome/panels/sandbox-panel.tsx +230 -0
- package/src/components/editor/chrome/panels/sandbox-toggle.tsx +52 -0
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +7 -0
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -1
- package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
- package/src/components/editor/code/readonly-diff.tsx +1 -1
- package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +98 -98
- package/src/components/editor/connections/database/__tests__/as-code.test.ts +11 -5
- package/src/components/editor/dynamic-favicon.tsx +17 -10
- package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +13 -11
- package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
- package/src/components/editor/file-tree/tree-actions.tsx +11 -14
- package/src/components/editor/header/__tests__/status.test.tsx +8 -20
- package/src/components/editor/header/filename-input.tsx +2 -0
- package/src/components/editor/header/status.tsx +5 -3
- package/src/components/editor/navigation/clipboard.ts +1 -0
- package/src/components/editor/notebook-cell.tsx +4 -2
- package/src/components/editor/output/JsonOutput.tsx +182 -632
- package/src/components/editor/output/Outputs.css +49 -17
- package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
- package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
- package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
- package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
- package/src/components/editor/output/json-output/formatting.ts +167 -0
- package/src/components/editor/output/json-output/pagination.ts +155 -0
- package/src/components/editor/output/json-output/renderers.tsx +196 -0
- package/src/components/editor/output/json-output/themes.ts +52 -0
- package/src/components/editor/package-alert.tsx +112 -66
- package/src/components/editor/renderers/cell-array.tsx +1 -5
- package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +3 -7
- package/src/components/slides/slide-form.tsx +1 -0
- package/src/components/slides/slide-notes-editor.tsx +1 -0
- package/src/components/tracing/tracing-spec.ts +1 -1
- package/src/components/ui/__tests__/badge.test.ts +6 -4
- package/src/components/ui/use-toast.ts +8 -0
- package/src/core/MarimoApp.tsx +0 -2
- package/src/core/ai/context/providers/__tests__/error.test.ts +16 -22
- package/src/core/alerts/__tests__/environment.test.ts +183 -0
- package/src/core/alerts/__tests__/state.test.tsx +240 -0
- package/src/core/alerts/environment.ts +57 -0
- package/src/core/alerts/state.ts +155 -99
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +296 -259
- package/src/core/cells/__tests__/apply-transaction.test.ts +34 -0
- package/src/core/cells/__tests__/cell.test.ts +61 -0
- package/src/core/cells/__tests__/cells.test.ts +182 -37
- package/src/core/cells/__tests__/document-changes.test.ts +39 -1
- package/src/core/cells/__tests__/outputs.test.tsx +117 -0
- package/src/core/cells/__tests__/pending-delete-service.test.tsx +4 -3
- package/src/core/cells/__tests__/session.test.ts +7 -0
- package/src/core/cells/cell.ts +9 -1
- package/src/core/cells/cells.ts +13 -18
- package/src/core/cells/document-changes.ts +11 -1
- package/src/core/cells/outputs.ts +66 -9
- package/src/core/cells/pending-delete-service.ts +12 -16
- package/src/core/cells/session.ts +2 -0
- package/src/core/cells/types.ts +2 -0
- package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +8 -16
- package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
- package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +4 -8
- package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
- package/src/core/codemirror/rtc/extension.ts +5 -2
- package/src/core/config/pair.ts +19 -0
- package/src/core/datasets/__tests__/data-source.test.ts +2 -0
- package/src/core/datasets/data-source-connections.ts +15 -10
- package/src/core/edit-app.tsx +8 -5
- package/src/core/errors/state.ts +1 -2
- package/src/core/export/__tests__/hooks.test.ts +1 -6
- package/src/core/islands/bootstrap.ts +3 -1
- package/src/core/islands/bridge.ts +3 -0
- package/src/core/islands/worker-factory.ts +2 -12
- package/src/core/kernel/messages.ts +2 -2
- package/src/core/network/__tests__/requests-network.test.ts +4 -3
- package/src/core/network/connection-notice.ts +117 -0
- package/src/core/network/connection.ts +19 -0
- package/src/core/network/requests-lazy.ts +3 -0
- package/src/core/network/requests-network.ts +12 -0
- package/src/core/network/requests-static.ts +3 -0
- package/src/core/network/requests-toasting.tsx +3 -0
- package/src/core/network/resolve.ts +2 -1
- package/src/core/network/types.ts +7 -0
- package/src/core/network/useConnectionNotice.ts +53 -0
- package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
- package/src/core/packages/__tests__/useSandboxController.test.tsx +246 -0
- package/src/core/packages/package-data.ts +35 -0
- package/src/core/packages/sandbox-state.ts +67 -0
- package/src/core/packages/toast-components.tsx +11 -0
- package/src/core/packages/useInstallPackage.ts +1 -1
- package/src/core/packages/usePackageAction.ts +51 -0
- package/src/core/packages/usePackageDependencies.ts +22 -0
- package/src/core/packages/useSandboxController.ts +208 -0
- package/src/core/run-app.tsx +2 -0
- package/src/core/static/__tests__/files.test.ts +12 -30
- package/src/core/wasm/__tests__/bootstrap.test.ts +63 -0
- package/src/core/wasm/__tests__/bridge.test.ts +13 -4
- package/src/core/wasm/__tests__/fs.test.ts +22 -0
- package/src/core/wasm/__tests__/runtime-config.test.ts +65 -0
- package/src/core/wasm/bridge.ts +35 -23
- package/src/core/wasm/rpc.ts +2 -0
- package/src/core/wasm/runtime-config.ts +31 -0
- package/src/core/wasm/worker/bootstrap.ts +21 -11
- package/src/core/wasm/worker/constants.ts +1 -0
- package/src/core/wasm/worker/fs.ts +4 -0
- package/src/core/wasm/worker/getController.ts +3 -1
- package/src/core/wasm/worker/save-worker.ts +10 -9
- package/src/core/wasm/worker/types.ts +6 -4
- package/src/core/wasm/worker/worker.ts +9 -9
- package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +404 -3
- package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +8 -6
- package/src/core/websocket/transports/transport.ts +1 -1
- package/src/core/websocket/transports/ws.ts +1 -1
- package/src/core/websocket/types.ts +11 -1
- package/src/core/websocket/useMarimoKernelConnection.tsx +63 -16
- package/src/hooks/useDebounce.ts +2 -0
- package/src/mount.tsx +3 -0
- package/src/plugins/core/BadPlugin.tsx +3 -14
- package/src/plugins/core/RenderHTML.tsx +22 -2
- package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
- package/src/plugins/core/registerReactComponent.tsx +0 -1
- package/src/plugins/impl/FileBrowserPlugin.tsx +10 -4
- package/src/plugins/impl/FormPlugin.tsx +2 -0
- package/src/plugins/impl/MatrixPlugin.tsx +2 -0
- package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
- package/src/plugins/impl/SliderPlugin.tsx +2 -0
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +50 -1
- package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
- package/src/plugins/impl/data-frames/panel.tsx +1 -0
- package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +1 -1
- package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +15 -0
- package/src/plugins/impl/vega/__tests__/make-selectable.test.ts +42 -48
- package/src/plugins/layout/AccordionPlugin.tsx +7 -2
- package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
- package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
- package/src/stories/sandbox.stories.tsx +488 -0
- package/src/utils/__tests__/path.test.ts +6 -5
- package/src/utils/__tests__/worker.test.ts +81 -0
- package/src/utils/worker.ts +22 -0
- package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
- package/dist/_baseMerge-Dv8bBloN.js +0 -73
- package/dist/_initCloneObject---vediN2.js +0 -95
- package/dist/arc-DOVLrCPd.js +0 -82
- package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
- package/dist/array-CApNbSU9.js +0 -6
- package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
- package/dist/assets/worker-DlIBfp9S.js +0 -98
- package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
- package/dist/chat-ui-BSwr409J.js +0 -8455
- package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
- package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
- package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
- package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
- package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
- package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
- package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
- package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
- package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
- package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
- package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
- package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
- package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
- package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
- package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
- package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
- package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
- package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
- package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
- package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
- package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
- package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
- package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
- package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
- package/dist/click-outside-container-D_URcm3D.js +0 -167
- package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
- package/dist/copy-CD7S58CY.js +0 -141
- package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
- package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
- package/dist/dist-3_o3T78I.js +0 -1360
- package/dist/dist-ABQjhuek.js +0 -64
- package/dist/dist-CO5R6VMi.js +0 -538
- package/dist/dropdown-menu-DhCfcscX.js +0 -5858
- package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
- package/dist/error-banner-CsXbEEjo.js +0 -611
- package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
- package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
- package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
- package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
- package/dist/line-CuKjIQa1.js +0 -34
- package/dist/map-BJpOfPlL.js +0 -149
- package/dist/math-BXtKgYah.js +0 -10
- package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
- package/dist/mermaid-Bi23Ibnw.js +0 -1173
- package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
- package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
- package/dist/path-BNHuHZP8.js +0 -87
- package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
- package/dist/purify.es-CB-YO1Hn.js +0 -774
- package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
- package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
- package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
- package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
- package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
- package/dist/schemas-DzK6U94N.js +0 -6057
- package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
- package/dist/step-CKczO72Q.js +0 -670
- package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
- package/dist/timer-DpDyj9G0.js +0 -596
- package/dist/tooltip-Dt77sBeT.js +0 -390
- package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
- package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
- package/dist/useTheme-CVJ0UOf2.js +0 -841
- package/dist/vega-loader.browser-DEggZzni.js +0 -1083
- package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
- package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
4
|
+
import type { PropsWithChildren, ReactNode } from "react";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { MockRequestClient } from "@/__mocks__/requests";
|
|
7
|
+
import { ModalProvider } from "@/components/modal/ImperativeModal";
|
|
8
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
9
|
+
import { clearToasts } from "@/components/ui/use-toast";
|
|
10
|
+
import { initialNotebookState, notebookAtom } from "@/core/cells/cells";
|
|
11
|
+
import { viewStateAtom } from "@/core/mode";
|
|
12
|
+
import { connectionAtom } from "@/core/network/connection";
|
|
13
|
+
import { requestClientAtom } from "@/core/network/requests";
|
|
14
|
+
import type { EnvironmentInfo } from "@/core/network/types";
|
|
15
|
+
import { filenameAtom } from "@/core/saving/file-state";
|
|
16
|
+
import { store } from "@/core/state/jotai";
|
|
17
|
+
import { WebSocketState } from "@/core/websocket/types";
|
|
18
|
+
import { ErrorBoundary } from "../ErrorBoundary";
|
|
19
|
+
|
|
20
|
+
vi.mock("@/utils/copy", () => ({
|
|
21
|
+
copyToClipboard: vi.fn().mockResolvedValue(undefined),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
const environment: EnvironmentInfo = {
|
|
25
|
+
marimo: "1.2.3",
|
|
26
|
+
editable: false,
|
|
27
|
+
location: "~/.venv/site-packages/marimo",
|
|
28
|
+
OS: "Darwin",
|
|
29
|
+
"OS Version": "25.0",
|
|
30
|
+
Processor: "arm",
|
|
31
|
+
"Python Version": "3.12.9",
|
|
32
|
+
Locale: "en_US",
|
|
33
|
+
Binaries: { Browser: "chrome 140", Node: "v22", uv: "0.11" },
|
|
34
|
+
Dependencies: { click: "8.4.2" },
|
|
35
|
+
"Optional Dependencies": { pandas: "3.0.0" },
|
|
36
|
+
"Experimental Flags": {},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const CRASH_MESSAGE = "cell output crashed";
|
|
40
|
+
|
|
41
|
+
function CrashingChild(): never {
|
|
42
|
+
throw new Error(CRASH_MESSAGE);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function RecoverableChild({ crash }: { crash: boolean }) {
|
|
46
|
+
if (crash) {
|
|
47
|
+
throw new Error(CRASH_MESSAGE);
|
|
48
|
+
}
|
|
49
|
+
return <p>recovered child</p>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function DescendantProviders({ children }: PropsWithChildren) {
|
|
53
|
+
return (
|
|
54
|
+
<TooltipProvider>
|
|
55
|
+
<ModalProvider>{children}</ModalProvider>
|
|
56
|
+
</TooltipProvider>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isExpectedReactExceptionOutput(args: unknown[]): boolean {
|
|
61
|
+
return args.some((arg) => {
|
|
62
|
+
if (arg instanceof Error) {
|
|
63
|
+
return arg.message.includes(CRASH_MESSAGE);
|
|
64
|
+
}
|
|
65
|
+
return (
|
|
66
|
+
typeof arg === "string" &&
|
|
67
|
+
(arg.includes(CRASH_MESSAGE) ||
|
|
68
|
+
arg.includes("The above error occurred") ||
|
|
69
|
+
arg.includes("React will try to recreate this component tree"))
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function suppressExpectedReactException() {
|
|
75
|
+
return vi.spyOn(console, "error").mockImplementation((...args) => {
|
|
76
|
+
if (isExpectedReactExceptionOutput(args)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`Unexpected console.error: ${args.map(String).join(" ")}`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let consoleError: ReturnType<typeof vi.spyOn> | undefined;
|
|
84
|
+
|
|
85
|
+
function renderCrashedBoundary(child: ReactNode = <CrashingChild />) {
|
|
86
|
+
consoleError?.mockRestore();
|
|
87
|
+
consoleError = suppressExpectedReactException();
|
|
88
|
+
return render(<ErrorBoundary>{child}</ErrorBoundary>);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function setRequestClient(
|
|
92
|
+
overrides?: Parameters<typeof MockRequestClient.create>[0],
|
|
93
|
+
) {
|
|
94
|
+
const client = MockRequestClient.create(overrides);
|
|
95
|
+
store.set(requestClientAtom, client);
|
|
96
|
+
return client;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function openReportDialog() {
|
|
100
|
+
const trigger = screen.getByRole("button", { name: "Report an issue" });
|
|
101
|
+
trigger.focus();
|
|
102
|
+
fireEvent.click(trigger);
|
|
103
|
+
return screen.findByRole("dialog");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function expectReportButtonFocused() {
|
|
107
|
+
await waitFor(() => {
|
|
108
|
+
expect(
|
|
109
|
+
screen.getByRole("button", { name: "Report an issue" }),
|
|
110
|
+
).toHaveFocus();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function closeReportDialog(method: "escape" | "close") {
|
|
115
|
+
const dialog = await screen.findByRole("dialog");
|
|
116
|
+
if (method === "escape") {
|
|
117
|
+
fireEvent.keyDown(dialog, { key: "Escape" });
|
|
118
|
+
} else {
|
|
119
|
+
fireEvent.click(screen.getByRole("button", { name: "Close" }));
|
|
120
|
+
}
|
|
121
|
+
await waitFor(() => {
|
|
122
|
+
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
|
|
123
|
+
});
|
|
124
|
+
await expectReportButtonFocused();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function expectRealReportModal() {
|
|
128
|
+
const dialog = await openReportDialog();
|
|
129
|
+
expect(dialog).toHaveTextContent("Report an issue");
|
|
130
|
+
expect(screen.getByRole("link", { name: "Open GitHub issue" })).toBeVisible();
|
|
131
|
+
expect(
|
|
132
|
+
screen.getByRole("checkbox", { name: "Include errors" }),
|
|
133
|
+
).toBeVisible();
|
|
134
|
+
expect(
|
|
135
|
+
screen.getByRole("checkbox", { name: "Include notebook code" }),
|
|
136
|
+
).toBeVisible();
|
|
137
|
+
await screen.findByText("Environment details");
|
|
138
|
+
return dialog;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function resetSharedState() {
|
|
142
|
+
localStorage.clear();
|
|
143
|
+
clearToasts();
|
|
144
|
+
store.set(requestClientAtom, null);
|
|
145
|
+
store.set(notebookAtom, initialNotebookState());
|
|
146
|
+
store.set(viewStateAtom, { mode: "edit", cellAnchor: null });
|
|
147
|
+
store.set(connectionAtom, { state: WebSocketState.OPEN });
|
|
148
|
+
store.set(filenameAtom, "/project/example.py");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
describe("ErrorBoundary report dialog", () => {
|
|
152
|
+
beforeEach(() => {
|
|
153
|
+
resetSharedState();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
afterEach(() => {
|
|
157
|
+
consoleError?.mockRestore();
|
|
158
|
+
consoleError = undefined;
|
|
159
|
+
resetSharedState();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("opens the report modal after a child render exception", async () => {
|
|
163
|
+
const { getEnvironmentInfo } = setRequestClient({
|
|
164
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
renderCrashedBoundary();
|
|
168
|
+
|
|
169
|
+
expect(screen.getByText("Something went wrong")).toBeVisible();
|
|
170
|
+
expect(screen.getByText("cell output crashed")).toBeVisible();
|
|
171
|
+
expect(screen.getByTestId("reset-error-boundary-button")).toBeVisible();
|
|
172
|
+
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
|
|
173
|
+
expect(getEnvironmentInfo).not.toHaveBeenCalled();
|
|
174
|
+
|
|
175
|
+
await expectRealReportModal();
|
|
176
|
+
await waitFor(() => expect(getEnvironmentInfo).toHaveBeenCalledOnce());
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("still opens one report dialog after descendant providers disappear", async () => {
|
|
180
|
+
const { getEnvironmentInfo } = setRequestClient({
|
|
181
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
renderCrashedBoundary(
|
|
185
|
+
<DescendantProviders>
|
|
186
|
+
<CrashingChild />
|
|
187
|
+
</DescendantProviders>,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
await expectRealReportModal();
|
|
191
|
+
expect(screen.getAllByRole("dialog")).toHaveLength(1);
|
|
192
|
+
await waitFor(() => expect(getEnvironmentInfo).toHaveBeenCalledOnce());
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("shows partial diagnostics when the request client is missing", async () => {
|
|
196
|
+
renderCrashedBoundary();
|
|
197
|
+
|
|
198
|
+
await openReportDialog();
|
|
199
|
+
await screen.findByText("Environment details");
|
|
200
|
+
|
|
201
|
+
expect(
|
|
202
|
+
screen.getByText("Server environment information unavailable"),
|
|
203
|
+
).toBeVisible();
|
|
204
|
+
expect(
|
|
205
|
+
screen.queryByText("Loading environment details…"),
|
|
206
|
+
).not.toBeInTheDocument();
|
|
207
|
+
expect(
|
|
208
|
+
screen.queryByRole("button", { name: "Retry" }),
|
|
209
|
+
).not.toBeInTheDocument();
|
|
210
|
+
expect(
|
|
211
|
+
screen.getByRole("checkbox", { name: "Include notebook code" }),
|
|
212
|
+
).toBeDisabled();
|
|
213
|
+
expect(screen.getByText("Notebook source is unavailable.")).toBeVisible();
|
|
214
|
+
const link = screen.getByRole("link", { name: "Open GitHub issue" });
|
|
215
|
+
expect(link.getAttribute("href") ?? "").toContain("&env=");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("does not request environment or source while the report dialog is closed", async () => {
|
|
219
|
+
localStorage.setItem(
|
|
220
|
+
"marimo:issue-report:include-code",
|
|
221
|
+
JSON.stringify(true),
|
|
222
|
+
);
|
|
223
|
+
const { getEnvironmentInfo, readCode } = setRequestClient({
|
|
224
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
225
|
+
readCode: vi.fn().mockResolvedValue({ contents: "import marimo" }),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
renderCrashedBoundary();
|
|
229
|
+
|
|
230
|
+
expect(screen.getByText("Something went wrong")).toBeVisible();
|
|
231
|
+
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
|
|
232
|
+
expect(getEnvironmentInfo).not.toHaveBeenCalled();
|
|
233
|
+
expect(readCode).not.toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("restores focus to the report button after closing with Escape", async () => {
|
|
237
|
+
setRequestClient({
|
|
238
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
239
|
+
});
|
|
240
|
+
renderCrashedBoundary();
|
|
241
|
+
await openReportDialog();
|
|
242
|
+
await closeReportDialog("escape");
|
|
243
|
+
expect(screen.getByText(CRASH_MESSAGE)).toBeVisible();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("restores focus to the report button after closing with the close control", async () => {
|
|
247
|
+
setRequestClient({
|
|
248
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
249
|
+
});
|
|
250
|
+
renderCrashedBoundary();
|
|
251
|
+
await openReportDialog();
|
|
252
|
+
await closeReportDialog("close");
|
|
253
|
+
expect(screen.getByText(CRASH_MESSAGE)).toBeVisible();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("reopens the report dialog while the original error remains", async () => {
|
|
257
|
+
setRequestClient({
|
|
258
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
259
|
+
});
|
|
260
|
+
renderCrashedBoundary();
|
|
261
|
+
await openReportDialog();
|
|
262
|
+
await closeReportDialog("escape");
|
|
263
|
+
expect(screen.getByText(CRASH_MESSAGE)).toBeVisible();
|
|
264
|
+
await expectRealReportModal();
|
|
265
|
+
expect(screen.getByText(CRASH_MESSAGE)).toBeVisible();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("restores the child after try again once the failure is cleared", () => {
|
|
269
|
+
setRequestClient({
|
|
270
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
271
|
+
});
|
|
272
|
+
const view = renderCrashedBoundary(<RecoverableChild crash={true} />);
|
|
273
|
+
expect(screen.getByText("Something went wrong")).toBeVisible();
|
|
274
|
+
|
|
275
|
+
view.rerender(
|
|
276
|
+
<ErrorBoundary>
|
|
277
|
+
<RecoverableChild crash={false} />
|
|
278
|
+
</ErrorBoundary>,
|
|
279
|
+
);
|
|
280
|
+
fireEvent.click(screen.getByTestId("reset-error-boundary-button"));
|
|
281
|
+
|
|
282
|
+
expect(screen.getByText("recovered child")).toBeVisible();
|
|
283
|
+
expect(screen.queryByText("Something went wrong")).not.toBeInTheDocument();
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("does not read notebook source when opened with fresh inclusion preferences", async () => {
|
|
287
|
+
const { readCode } = setRequestClient({
|
|
288
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
289
|
+
readCode: vi.fn().mockResolvedValue({ contents: "import marimo" }),
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
renderCrashedBoundary();
|
|
293
|
+
await expectRealReportModal();
|
|
294
|
+
|
|
295
|
+
expect(readCode).not.toHaveBeenCalled();
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("renders the copy toast after the ancestor toaster is gone", async () => {
|
|
299
|
+
setRequestClient({
|
|
300
|
+
getEnvironmentInfo: vi.fn().mockResolvedValue(environment),
|
|
301
|
+
});
|
|
302
|
+
renderCrashedBoundary();
|
|
303
|
+
await expectRealReportModal();
|
|
304
|
+
|
|
305
|
+
fireEvent.click(
|
|
306
|
+
screen.getByRole("button", { name: "Copy environment JSON" }),
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
expect(await screen.findByText("Environment details copied")).toBeVisible();
|
|
310
|
+
});
|
|
311
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { ToolbarItem } from "../toolbar";
|
|
6
|
+
|
|
7
|
+
describe("ToolbarItem keyboard activation", () => {
|
|
8
|
+
it.each(["Enter", " "])(
|
|
9
|
+
"keeps native %s activation out of cell navigation and calls the consumer handler",
|
|
10
|
+
(key) => {
|
|
11
|
+
const onCellKeyDown = vi.fn();
|
|
12
|
+
const onKeyDown = vi.fn();
|
|
13
|
+
render(
|
|
14
|
+
<div onKeyDown={onCellKeyDown}>
|
|
15
|
+
<ToolbarItem tooltip={null} onKeyDown={onKeyDown}>
|
|
16
|
+
Run
|
|
17
|
+
</ToolbarItem>
|
|
18
|
+
</div>,
|
|
19
|
+
);
|
|
20
|
+
const button = screen.getByRole("button", { name: "Run" });
|
|
21
|
+
|
|
22
|
+
expect(fireEvent.keyDown(button, { key })).toBe(true);
|
|
23
|
+
expect(onCellKeyDown).not.toHaveBeenCalled();
|
|
24
|
+
expect(onKeyDown).toHaveBeenCalledOnce();
|
|
25
|
+
expect(onKeyDown.mock.calls[0][0].defaultPrevented).toBe(false);
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
it.each([
|
|
30
|
+
{ key: "Enter", ctrlKey: true },
|
|
31
|
+
{ key: "Enter", metaKey: true },
|
|
32
|
+
{ key: "Enter", shiftKey: true },
|
|
33
|
+
{ key: "Enter", altKey: true },
|
|
34
|
+
{ key: " ", ctrlKey: true },
|
|
35
|
+
{ key: "ArrowLeft" },
|
|
36
|
+
{ key: "ArrowRight" },
|
|
37
|
+
{ key: "Tab" },
|
|
38
|
+
{ key: "Escape" },
|
|
39
|
+
])("preserves propagation for %j", (event) => {
|
|
40
|
+
const onCellKeyDown = vi.fn();
|
|
41
|
+
render(
|
|
42
|
+
<div onKeyDown={onCellKeyDown}>
|
|
43
|
+
<ToolbarItem tooltip={null}>Run</ToolbarItem>
|
|
44
|
+
</div>,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(fireEvent.keyDown(screen.getByRole("button"), event)).toBe(true);
|
|
48
|
+
expect(onCellKeyDown).toHaveBeenCalledOnce();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("does not submit forms and preserves disabled and mouse-focus behavior", () => {
|
|
52
|
+
const onClick = vi.fn();
|
|
53
|
+
const { rerender } = render(
|
|
54
|
+
<ToolbarItem tooltip={null} onClick={onClick}>
|
|
55
|
+
Run
|
|
56
|
+
</ToolbarItem>,
|
|
57
|
+
);
|
|
58
|
+
const button = screen.getByRole("button");
|
|
59
|
+
expect(button).toHaveAttribute("type", "button");
|
|
60
|
+
expect(fireEvent.mouseDown(button)).toBe(false);
|
|
61
|
+
fireEvent.click(button);
|
|
62
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
63
|
+
|
|
64
|
+
rerender(
|
|
65
|
+
<ToolbarItem tooltip={null} onClick={onClick} disabled={true}>
|
|
66
|
+
Run
|
|
67
|
+
</ToolbarItem>,
|
|
68
|
+
);
|
|
69
|
+
expect(button).toBeDisabled();
|
|
70
|
+
fireEvent.click(button);
|
|
71
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { EditorState } from "@codemirror/state";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { composeRtcEditorConfig } from "../cell-editor";
|
|
6
|
+
|
|
7
|
+
describe("composeRtcEditorConfig", () => {
|
|
8
|
+
it("does not accumulate RTC extensions across reconfigurations", () => {
|
|
9
|
+
const baseExtension = EditorState.readOnly.of(false);
|
|
10
|
+
const baseExtensions = [baseExtension];
|
|
11
|
+
const firstRtc = {
|
|
12
|
+
code: "first RTC code",
|
|
13
|
+
extension: EditorState.tabSize.of(2),
|
|
14
|
+
};
|
|
15
|
+
const secondRtc = {
|
|
16
|
+
code: "second RTC code",
|
|
17
|
+
extension: EditorState.tabSize.of(4),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const firstConfig = composeRtcEditorConfig(
|
|
21
|
+
"local code",
|
|
22
|
+
baseExtensions,
|
|
23
|
+
firstRtc,
|
|
24
|
+
);
|
|
25
|
+
const secondConfig = composeRtcEditorConfig(
|
|
26
|
+
"local code",
|
|
27
|
+
baseExtensions,
|
|
28
|
+
secondRtc,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(baseExtensions).toEqual([baseExtension]);
|
|
32
|
+
expect(firstConfig).toEqual({
|
|
33
|
+
code: firstRtc.code,
|
|
34
|
+
extensions: [baseExtension, firstRtc.extension],
|
|
35
|
+
});
|
|
36
|
+
expect(secondConfig).toEqual({
|
|
37
|
+
code: secondRtc.code,
|
|
38
|
+
extensions: [baseExtension, secondRtc.extension],
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("reuses the base configuration when RTC is disabled", () => {
|
|
43
|
+
const extensions = [EditorState.readOnly.of(false)];
|
|
44
|
+
|
|
45
|
+
const config = composeRtcEditorConfig("local code", extensions, undefined);
|
|
46
|
+
|
|
47
|
+
expect(config).toEqual({ code: "local code", extensions });
|
|
48
|
+
expect(config.extensions).toBe(extensions);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { historyField } from "@codemirror/commands";
|
|
3
|
-
import { EditorState, StateEffect } from "@codemirror/state";
|
|
3
|
+
import { EditorState, type Extension, StateEffect } from "@codemirror/state";
|
|
4
4
|
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
5
5
|
import { useIntersectionObserver } from "@uidotdev/usehooks";
|
|
6
6
|
import { useAtom, useAtomValue } from "jotai";
|
|
@@ -95,6 +95,21 @@ export interface CellEditorProps
|
|
|
95
95
|
tooltipParentSelector?: string;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
export function composeRtcEditorConfig(
|
|
99
|
+
code: string,
|
|
100
|
+
extensions: Extension[],
|
|
101
|
+
rtc: ReturnType<typeof realTimeCollaboration> | undefined,
|
|
102
|
+
): { code: string; extensions: Extension[] } {
|
|
103
|
+
if (!rtc) {
|
|
104
|
+
return { code, extensions };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
code: rtc.code,
|
|
109
|
+
extensions: [...extensions, rtc.extension],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
98
113
|
const CellEditorInternal = ({
|
|
99
114
|
theme,
|
|
100
115
|
showPlaceholder,
|
|
@@ -343,27 +358,31 @@ const CellEditorInternal = ({
|
|
|
343
358
|
]);
|
|
344
359
|
|
|
345
360
|
const rtcEnabled = isRtcEnabled() && canUseRtc(cellId);
|
|
346
|
-
const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const rtc = realTimeCollaboration(
|
|
350
|
-
cellId,
|
|
351
|
-
(code) => {
|
|
352
|
-
// It's not really a formatting change,
|
|
353
|
-
// but this means it won't be marked as stale
|
|
354
|
-
cellActions.updateCellCode({ cellId, code, formattingChange: true });
|
|
355
|
-
},
|
|
356
|
-
code,
|
|
357
|
-
);
|
|
358
|
-
extensions.push(rtc.extension);
|
|
359
|
-
code = rtc.code;
|
|
361
|
+
const createEditorConfig = (initialCode?: string) => {
|
|
362
|
+
if (!rtcEnabled) {
|
|
363
|
+
return composeRtcEditorConfig(code, extensions, undefined);
|
|
360
364
|
}
|
|
361
365
|
|
|
366
|
+
const rtc = realTimeCollaboration(
|
|
367
|
+
cellId,
|
|
368
|
+
(code) => {
|
|
369
|
+
// It's not really a formatting change,
|
|
370
|
+
// but this means it won't be marked as stale
|
|
371
|
+
cellActions.updateCellCode({ cellId, code, formattingChange: true });
|
|
372
|
+
},
|
|
373
|
+
initialCode,
|
|
374
|
+
);
|
|
375
|
+
return composeRtcEditorConfig(code, extensions, rtc);
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
const handleInitializeEditor = useEvent(() => {
|
|
379
|
+
const editorConfig = createEditorConfig(code);
|
|
380
|
+
|
|
362
381
|
// Create a new editor
|
|
363
382
|
const ev = new EditorView({
|
|
364
383
|
state: EditorState.create({
|
|
365
|
-
doc: code,
|
|
366
|
-
extensions: extensions,
|
|
384
|
+
doc: editorConfig.code,
|
|
385
|
+
extensions: editorConfig.extensions,
|
|
367
386
|
}),
|
|
368
387
|
});
|
|
369
388
|
setEditorView(ev);
|
|
@@ -377,19 +396,11 @@ const CellEditorInternal = ({
|
|
|
377
396
|
|
|
378
397
|
const handleReconfigureEditor = useEvent(() => {
|
|
379
398
|
invariant(editorViewRef.current !== null, "Editor view is not initialized");
|
|
380
|
-
|
|
381
|
-
if (rtcEnabled) {
|
|
382
|
-
const rtc = realTimeCollaboration(cellId, (code) => {
|
|
383
|
-
// It's not really a formatting change,
|
|
384
|
-
// but this means it won't be marked as stale
|
|
385
|
-
cellActions.updateCellCode({ cellId, code, formattingChange: true });
|
|
386
|
-
});
|
|
387
|
-
extensions.push(rtc.extension);
|
|
388
|
-
}
|
|
399
|
+
const editorConfig = createEditorConfig();
|
|
389
400
|
|
|
390
401
|
editorViewRef.current.dispatch({
|
|
391
402
|
effects: [
|
|
392
|
-
StateEffect.reconfigure.of([extensions]),
|
|
403
|
+
StateEffect.reconfigure.of([editorConfig.extensions]),
|
|
393
404
|
reconfigureLanguageEffect(editorViewRef.current, {
|
|
394
405
|
completionConfig: userConfig.completion,
|
|
395
406
|
hotkeysProvider: new OverridingHotkeyProvider(
|
|
@@ -406,26 +417,14 @@ const CellEditorInternal = ({
|
|
|
406
417
|
|
|
407
418
|
const handleDeserializeEditor = useEvent(() => {
|
|
408
419
|
invariant(serializedEditorState, "Editor view is not initialized");
|
|
409
|
-
|
|
410
|
-
const rtc = realTimeCollaboration(
|
|
411
|
-
cellId,
|
|
412
|
-
(code) => {
|
|
413
|
-
// It's not really a formatting change,
|
|
414
|
-
// but this means it won't be marked as stale
|
|
415
|
-
cellActions.updateCellCode({ cellId, code, formattingChange: true });
|
|
416
|
-
},
|
|
417
|
-
code,
|
|
418
|
-
);
|
|
419
|
-
extensions.push(rtc.extension);
|
|
420
|
-
code = rtc.code;
|
|
421
|
-
}
|
|
420
|
+
const editorConfig = createEditorConfig(code);
|
|
422
421
|
|
|
423
422
|
const ev = new EditorView({
|
|
424
423
|
state: EditorState.fromJSON(
|
|
425
424
|
serializedEditorState,
|
|
426
425
|
{
|
|
427
|
-
doc: code,
|
|
428
|
-
extensions: extensions,
|
|
426
|
+
doc: editorConfig.code,
|
|
427
|
+
extensions: editorConfig.extensions,
|
|
429
428
|
},
|
|
430
429
|
{ history: historyField },
|
|
431
430
|
),
|
|
@@ -43,8 +43,19 @@ export const ToolbarItem: React.FC<ToolbarItemProps> = ({
|
|
|
43
43
|
}) => {
|
|
44
44
|
const content = (
|
|
45
45
|
<button
|
|
46
|
+
type="button"
|
|
46
47
|
disabled={disabled}
|
|
47
48
|
{...rest}
|
|
49
|
+
onKeyDown={(evt) => {
|
|
50
|
+
// Preserve native button activation without triggering cell navigation.
|
|
51
|
+
if (
|
|
52
|
+
!Events.hasModifier(evt) &&
|
|
53
|
+
(evt.key === "Enter" || evt.key === " ")
|
|
54
|
+
) {
|
|
55
|
+
evt.stopPropagation();
|
|
56
|
+
}
|
|
57
|
+
rest.onKeyDown?.(evt);
|
|
58
|
+
}}
|
|
48
59
|
onClick={(evt) => {
|
|
49
60
|
if (!disabled) {
|
|
50
61
|
rest.onClick?.(evt);
|
|
@@ -208,4 +208,98 @@ describe("FeedbackModal issue reporting", () => {
|
|
|
208
208
|
expect(href).toContain(encodeURIComponent('"marimo": "1.2.3"'));
|
|
209
209
|
});
|
|
210
210
|
});
|
|
211
|
+
|
|
212
|
+
it("shows partial environment details when the request client is missing", async () => {
|
|
213
|
+
store.set(requestClientAtom, null);
|
|
214
|
+
render(<FeedbackModal onClose={vi.fn()} />, { wrapper });
|
|
215
|
+
|
|
216
|
+
await screen.findByText("Environment details");
|
|
217
|
+
expect(
|
|
218
|
+
screen.getByText("Server environment information unavailable"),
|
|
219
|
+
).toBeInTheDocument();
|
|
220
|
+
expect(
|
|
221
|
+
screen.queryByText("Loading environment details…"),
|
|
222
|
+
).not.toBeInTheDocument();
|
|
223
|
+
expect(
|
|
224
|
+
screen.queryByRole("button", { name: "Retry" }),
|
|
225
|
+
).not.toBeInTheDocument();
|
|
226
|
+
|
|
227
|
+
const link = screen.getByRole("link", { name: "Open GitHub issue" });
|
|
228
|
+
const href = link.getAttribute("href") ?? "";
|
|
229
|
+
expect(href).toContain("&env=");
|
|
230
|
+
expect(href).toContain(encodeURIComponent("Environment Collection Error"));
|
|
231
|
+
|
|
232
|
+
fireEvent.click(
|
|
233
|
+
screen.getByRole("button", { name: "Copy environment JSON" }),
|
|
234
|
+
);
|
|
235
|
+
await waitFor(() =>
|
|
236
|
+
expect(copyModule.copyToClipboard).toHaveBeenCalledWith(
|
|
237
|
+
expect.stringContaining("Environment Collection Error"),
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("disables source collection when the request client is missing", async () => {
|
|
243
|
+
localStorage.setItem(
|
|
244
|
+
"marimo:issue-report:include-code",
|
|
245
|
+
JSON.stringify(true),
|
|
246
|
+
);
|
|
247
|
+
store.set(connectionAtom, { state: WebSocketState.CONNECTING });
|
|
248
|
+
store.set(requestClientAtom, null);
|
|
249
|
+
render(<FeedbackModal onClose={vi.fn()} />, { wrapper });
|
|
250
|
+
|
|
251
|
+
await screen.findByText("Environment details");
|
|
252
|
+
expect(
|
|
253
|
+
screen.getByRole("checkbox", { name: "Include notebook code" }),
|
|
254
|
+
).toBeDisabled();
|
|
255
|
+
expect(
|
|
256
|
+
screen.getByText("Notebook source is unavailable."),
|
|
257
|
+
).toBeInTheDocument();
|
|
258
|
+
expect(
|
|
259
|
+
screen.queryByText("Connect the notebook to include its source."),
|
|
260
|
+
).not.toBeInTheDocument();
|
|
261
|
+
const link = screen.getByRole("link", { name: "Open GitHub issue" });
|
|
262
|
+
expect(link.getAttribute("href") ?? "").not.toContain("reproduction-code=");
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("preserves partial diagnostics when the environment request throws", async () => {
|
|
266
|
+
store.set(
|
|
267
|
+
requestClientAtom,
|
|
268
|
+
MockRequestClient.create({
|
|
269
|
+
getEnvironmentInfo: vi.fn().mockImplementation(() => {
|
|
270
|
+
throw new Error("offline");
|
|
271
|
+
}),
|
|
272
|
+
}),
|
|
273
|
+
);
|
|
274
|
+
render(<FeedbackModal onClose={vi.fn()} />, { wrapper });
|
|
275
|
+
|
|
276
|
+
await screen.findByText("Server environment information unavailable");
|
|
277
|
+
expect(screen.getByRole("button", { name: "Retry" })).toBeInTheDocument();
|
|
278
|
+
expect(
|
|
279
|
+
screen.getByText(/Environment Collection Error/),
|
|
280
|
+
).toBeInTheDocument();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("replaces partial diagnostics after a successful environment retry", async () => {
|
|
284
|
+
const getEnvironmentInfo = vi
|
|
285
|
+
.fn()
|
|
286
|
+
.mockRejectedValueOnce(new Error("offline"))
|
|
287
|
+
.mockResolvedValueOnce(environment);
|
|
288
|
+
store.set(
|
|
289
|
+
requestClientAtom,
|
|
290
|
+
MockRequestClient.create({ getEnvironmentInfo }),
|
|
291
|
+
);
|
|
292
|
+
render(<FeedbackModal onClose={vi.fn()} />, { wrapper });
|
|
293
|
+
|
|
294
|
+
await screen.findByText("Server environment information unavailable");
|
|
295
|
+
fireEvent.click(screen.getByRole("button", { name: "Retry" }));
|
|
296
|
+
|
|
297
|
+
await screen.findByText(/"marimo": "1.2.3"/);
|
|
298
|
+
expect(
|
|
299
|
+
screen.queryByText("Server environment information unavailable"),
|
|
300
|
+
).not.toBeInTheDocument();
|
|
301
|
+
expect(
|
|
302
|
+
screen.queryByRole("button", { name: "Retry" }),
|
|
303
|
+
).not.toBeInTheDocument();
|
|
304
|
+
});
|
|
211
305
|
});
|