@marimo-team/islands 0.20.5-dev6 → 0.20.5-dev60
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/{Combination-Du-o_hC9.js → Combination-Dk6JxauT.js} +1 -1
- package/dist/{ConnectedDataExplorerComponent-DUS-zJoR.js → ConnectedDataExplorerComponent-DzTQ52Zs.js} +11 -11
- package/dist/{_baseIsEqual-5cAxzk6f.js → _baseIsEqual-CvgsjYoW.js} +38 -38
- package/dist/{_basePickBy-3JVb5wYm.js → _basePickBy-pTDW2_2A.js} +6 -6
- package/dist/{_baseUniq-DSSiFuIJ.js → _baseUniq-BUFhl85h.js} +1 -1
- package/dist/{any-language-editor-BL9o7y0_.js → any-language-editor-BIj11a2e.js} +19 -19
- package/dist/{architecture-7HQA4BMR-BxkNpYRp.js → architecture-7HQA4BMR-BmtmhGMc.js} +2 -2
- package/dist/{architectureDiagram-VXUJARFQ-DrJeyFHq.js → architectureDiagram-VXUJARFQ-Df0FNeBR.js} +14 -14
- package/dist/{blockDiagram-VD42YOAC-BJrP6qKc.js → blockDiagram-VD42YOAC-DszWqlLz.js} +7 -7
- package/dist/{button-KYalaJYu.js → button-DQpBib29.js} +24 -11
- package/dist/{c4Diagram-YG6GDRKO-Bo4gytQ5.js → c4Diagram-YG6GDRKO-Dyj8LoUX.js} +4 -4
- package/dist/{channel-IWLGkaBE.js → channel-CUFaIkTh.js} +1 -1
- package/dist/{check-C50jsehH.js → check-DpqPQmzz.js} +1 -1
- package/dist/{chunk-4F5CHEZ2-CxKDFd-t.js → chunk-4F5CHEZ2-CRwwZ2ED.js} +1 -1
- package/dist/{chunk-ABZYJK2D-CRwanrkd.js → chunk-ABZYJK2D-7QYXAAhe.js} +1 -1
- package/dist/{chunk-ATLVNIR6-CMMCMvOK.js → chunk-ATLVNIR6-pmHPAPSd.js} +1 -1
- package/dist/{chunk-B2363JML-e_W7KW1D.js → chunk-B2363JML-BuBMltZc.js} +1 -1
- package/dist/{chunk-B4BG7PRW-BNsHrGHG.js → chunk-B4BG7PRW-Dbta9cTX.js} +4 -4
- package/dist/{chunk-DI55MBZ5-DQeYbfMV.js → chunk-DI55MBZ5-DyKB35wC.js} +4 -4
- package/dist/{chunk-EXTU4WIE-CV_DQeaX.js → chunk-EXTU4WIE-BRFl4iNd.js} +1 -1
- package/dist/{chunk-FRFDVMJY-C7q09nvl.js → chunk-FRFDVMJY-Bk2LD5Te.js} +1 -1
- package/dist/{chunk-JA3XYJ7Z-Cmt--e0q.js → chunk-JA3XYJ7Z-BkrY9SdL.js} +2 -2
- package/dist/{chunk-JZLCHNYA-CkyMJnI9.js → chunk-JZLCHNYA-Bk_Lil-q.js} +4 -4
- package/dist/{chunk-N4CR4FBY-BJfHtJbD.js → chunk-N4CR4FBY-f5n6meOd.js} +5 -5
- package/dist/{chunk-PL6DKKU2-ChKBqnoD.js → chunk-PL6DKKU2-DiFkzMfM.js} +1 -1
- package/dist/{chunk-QN33PNHL-WOLIPUAJ.js → chunk-QN33PNHL-CXfJywHv.js} +1 -1
- package/dist/{chunk-QXUST7PY-DYuD50pU.js → chunk-QXUST7PY-D7-26sj3.js} +5 -5
- package/dist/{chunk-S3R3BYOJ-CsnX6RKs.js → chunk-S3R3BYOJ-BRT9vd1R.js} +3 -3
- package/dist/{chunk-SJTYNZTY-j6_1s5om.js → chunk-SJTYNZTY-BvVkbShU.js} +1 -1
- package/dist/{chunk-TCCFYFTB-DdLCbCTn.js → chunk-TCCFYFTB-DqxhgXG0.js} +31 -31
- package/dist/{chunk-TQ3KTPDO-CGsUIC73.js → chunk-TQ3KTPDO-CPkEruAA.js} +1 -1
- package/dist/{chunk-TZMSLE5B-B3eYTGCw.js → chunk-TZMSLE5B-DSfBOnzx.js} +1 -1
- package/dist/{chunk-UMXZTB3W--LdAK3Bv.js → chunk-UMXZTB3W-C4ypIY3V.js} +1 -1
- package/dist/{classDiagram-v2-WZHVMYZB-UTw37Gg8.js → classDiagram-2ON5EDUG-DphiMW3Y.js} +10 -10
- package/dist/{classDiagram-2ON5EDUG-C7C-oefv.js → classDiagram-v2-WZHVMYZB-BH1x5h4a.js} +10 -10
- package/dist/{clone-BJrS4PdE.js → clone-CEQ-pda1.js} +1 -1
- package/dist/{constants-D1Tbg_6B.js → constants-CytQ_3LM.js} +3 -3
- package/dist/{copy-oc-FcZzt.js → copy-BkBF0Xgk.js} +2 -2
- package/dist/{dagre-6UL2VRFP-BgsUhJrV.js → dagre-6UL2VRFP-DGEbtmgU.js} +12 -12
- package/dist/{dagre-CyZCGfV_.js → dagre-BVnNvbvD.js} +37 -37
- package/dist/{diagram-PSM6KHXK-BIUUOfKo.js → diagram-PSM6KHXK-CG_usglE.js} +15 -15
- package/dist/{diagram-QEK2KX5R-BFjolZQv.js → diagram-QEK2KX5R-CtGFEwzJ.js} +13 -13
- package/dist/{diagram-S2PKOQOG-4jfkWoZw.js → diagram-S2PKOQOG-ClKAGmbv.js} +13 -13
- package/dist/dist-B4MxkKHf.js +8 -0
- package/dist/{dist-De9X_Des.js → dist-B9EjSb9T.js} +1 -1
- package/dist/{dist-IW_ARJ3S.js → dist-BFxYppVR.js} +4 -4
- package/dist/{dist-D7ZGWV_9.js → dist-BGZ7TWS9.js} +3 -3
- package/dist/{dist-CwtEWuFb.js → dist-BSfYc7vq.js} +2 -2
- package/dist/{dist-DMS81OrU.js → dist-BUrWeMEP.js} +1 -1
- package/dist/dist-BYghZv6b.js +5 -0
- package/dist/dist-Be-uQhz5.js +6 -0
- package/dist/{dist-Ch_JuCvc.js → dist-BpMlUdNO.js} +3 -3
- package/dist/{dist-C6z8U-ms.js → dist-Bq5eYK43.js} +2 -2
- package/dist/{dist-BFL9TlzD.js → dist-Bq9zYwJs.js} +5 -5
- package/dist/{dist-7ZF--V_D.js → dist-C4K7pumm.js} +2 -2
- package/dist/{dist-Qjf6pcqK.js → dist-CAKwXCWI.js} +2 -2
- package/dist/dist-CB_xf0ju.js +5 -0
- package/dist/{dist-BwQHkjA9.js → dist-CDHl2i1x.js} +4 -4
- package/dist/dist-CK0qFAbF.js +8 -0
- package/dist/{dist-C4XMUaob.js → dist-CPlGUbk-.js} +2 -2
- package/dist/{dist-BT6_J2eq.js → dist-CSEWGuDq.js} +7 -2
- package/dist/dist-CYEk-qrr.js +8 -0
- package/dist/{dist-CYo3w-nC.js → dist-Cl5iM8xL.js} +3 -3
- package/dist/dist-CmKoWpMk.js +5 -0
- package/dist/{dist-I8MQW60_.js → dist-CseYuPtL.js} +2 -2
- package/dist/dist-D1nf4IQl.js +5 -0
- package/dist/{dist-CsqiXw7J.js → dist-D4gcY469.js} +2 -2
- package/dist/{dist-DUxS2paD.js → dist-D5NMgbbv.js} +2 -2
- package/dist/{dist-UYm1IE5s.js → dist-DERtJN02.js} +2 -2
- package/dist/{dist-CFToYDWO.js → dist-DEj2X26M.js} +2 -2
- package/dist/{dist-BuapEdlD.js → dist-DOoqn-VL.js} +70 -67
- package/dist/{dist-BLThQiU4.js → dist-DUretbKK.js} +2 -2
- package/dist/{dist-DEFZ7dnD.js → dist-D_-CGmlh.js} +2 -2
- package/dist/dist-Df3AcKpt.js +6 -0
- package/dist/dist-DgaFHt_I.js +5 -0
- package/dist/dist-Dk10C3ui.js +5 -0
- package/dist/{dist-D0f6Yrrb.js → dist-DodLQWPg.js} +1 -1
- package/dist/dist-DtyPVMHR.js +5 -0
- package/dist/{dist-Cb3cLT39.js → dist-HoZO6brh.js} +2 -2
- package/dist/{dist-Cqpjy6bK.js → dist-RNGn_-uD.js} +1 -1
- package/dist/{dist-BBcqvpvP.js → dist-Ux6dL_VB.js} +1 -1
- package/dist/{dist-B8Y11RWn.js → dist-WIWVvdBh.js} +2 -2
- package/dist/{dist-CB6qhQ8K.js → dist-gc9KgJuA.js} +1 -1
- package/dist/{dist-ovDpXuSB.js → dist-i-ud9aCA.js} +1 -1
- package/dist/dist-ko7WnHAO.js +5 -0
- package/dist/{dist-BTQbjEKU.js → dist-lNe4i1Nm.js} +1 -1
- package/dist/dist-of7gLRFK.js +8 -0
- package/dist/{erDiagram-Q2GNP2WA-Cq5Bz5lG.js → erDiagram-Q2GNP2WA-DPMseVVp.js} +10 -10
- package/dist/{error-banner-D0tXnwl4.js → error-banner-BctofTCP.js} +2 -2
- package/dist/{esm-BxMbHo0y.js → esm-BBkPJL8N.js} +29 -27
- package/dist/{flowDiagram-NV44I4VS-6WPJVFl7.js → flowDiagram-NV44I4VS-BpAIFwW7.js} +10 -10
- package/dist/{ganttDiagram-JELNMOA3-AfDhh9CI.js → ganttDiagram-JELNMOA3-DXYghZ9C.js} +3 -3
- package/dist/{gitGraph-G5XIXVHT-C0o6gecv.js → gitGraph-G5XIXVHT-ChHUSAop.js} +2 -2
- package/dist/{gitGraphDiagram-V2S2FVAM-BRSwuj0Q.js → gitGraphDiagram-V2S2FVAM-CBL-7g3_.js} +12 -12
- package/dist/{glide-data-editor-ByPNTNVG.js → glide-data-editor-DAqhWGKz.js} +63 -63
- package/dist/{graphlib-DZnBMcsX.js → graphlib-D18eZCT4.js} +10 -10
- package/dist/hasIn-B9AbGLj3.js +86 -0
- package/dist/{info-VBDWY6EO-Bzsods6X.js → info-VBDWY6EO-CwyXEo8E.js} +2 -2
- package/dist/{infoDiagram-HS3SLOUP-Cmxo6jKx.js → infoDiagram-HS3SLOUP-BXGbfBss.js} +12 -12
- package/dist/{isArrayLikeObject-Btu-i6_P.js → isArrayLikeObject-BrYl-ETg.js} +25 -26
- package/dist/{isEmpty-CZvUtYFp.js → isEmpty-C-xMag79.js} +2 -2
- package/dist/{isString-CBr7TEb7.js → isString-D-vNYDBA.js} +1 -1
- package/dist/{isSymbol-BuQsMXhk.js → isSymbol-Dyt2NSnN.js} +1 -1
- package/dist/{journeyDiagram-XKPGCS4Q-CKYr8cSR.js → journeyDiagram-XKPGCS4Q-D5BIjS4N.js} +3 -3
- package/dist/{kanban-definition-3W4ZIXB7-DVvAZzQD.js → kanban-definition-3W4ZIXB7-DhDkqxFB.js} +7 -7
- package/dist/{label-CV0KYhtH.js → label-BLDcDYdI.js} +6 -6
- package/dist/{loader-eJCvvApN.js → loader-DsE3MiYo.js} +2 -2
- package/dist/main.js +1587 -1108
- package/dist/{memoize-P1T1IGb9.js → memoize-Cs8aS5RW.js} +1 -1
- package/dist/merge-NuyC7LN7.js +51 -0
- package/dist/{mermaid-COOB_abB.js → mermaid-m5QS9ELR.js} +42 -42
- package/dist/{mermaid-parser.core-Cd-wu4tE.js → mermaid-parser.core-OkWZ8nr-.js} +8 -8
- package/dist/{min-CMDDtXJP.js → min-ECVRnCdn.js} +30 -30
- package/dist/{mindmap-definition-VGOIOE7T-1ExmnvYy.js → mindmap-definition-VGOIOE7T-BxQi78Vl.js} +9 -9
- package/dist/{now-BxlRp0OQ.js → now-BC2mX0ZT.js} +1 -1
- package/dist/{packet-DYOGHKS2-Bf1CvFco.js → packet-DYOGHKS2-C62XQjZh.js} +2 -2
- package/dist/{pie-VRWISCQL-LY_wbqji.js → pie-VRWISCQL-nfAKQJw3.js} +2 -2
- package/dist/{pieDiagram-ADFJNKIX-CJlIsdsU.js → pieDiagram-ADFJNKIX-DfSJXUHa.js} +13 -13
- package/dist/{purify.es-CyOIw8ru.js → purify.es-DGenX2XH.js} +67 -67
- package/dist/{quadrantDiagram-AYHSOK5B-BU78RiaH.js → quadrantDiagram-AYHSOK5B-CAcVWXc-.js} +2 -2
- package/dist/{radar-ZZBFDIW7-Ro3iXZCk.js → radar-ZZBFDIW7-lopS8_4j.js} +2 -2
- package/dist/{range-Dh0_-r8P.js → range-BKaWvVUE.js} +8 -8
- package/dist/reduce-CqQo8ppc.js +275 -0
- package/dist/{requirementDiagram-UZGBJVZJ-DACHtrFr.js → requirementDiagram-UZGBJVZJ-BU7dwzFM.js} +9 -9
- package/dist/{sankeyDiagram-TZEHDZUN-Bzg7_UWs.js → sankeyDiagram-TZEHDZUN-BVJnR4_b.js} +2 -2
- package/dist/{sequenceDiagram-WL72ISMW-agybEe9J.js → sequenceDiagram-WL72ISMW-CQcFQTwX.js} +4 -4
- package/dist/{slides-component-B0yK5GXP.js → slides-component-DwvL_HJi.js} +2 -2
- package/dist/{spec-Dq_reDGM.js → spec-DOGtAWuU.js} +5 -5
- package/dist/{stateDiagram-FKZM4ZOC-DehQAt8g.js → stateDiagram-FKZM4ZOC-Dx9AIGDe.js} +12 -12
- package/dist/{stateDiagram-v2-4FDKWEC3-8VzeREl9.js → stateDiagram-v2-4FDKWEC3-BIeUs-Ed.js} +10 -10
- package/dist/style.css +1 -1
- package/dist/{timeline-definition-IT6M3QCI-CdCfdaCF.js → timeline-definition-IT6M3QCI-D8B3p7ID.js} +2 -2
- package/dist/{toNumber-By7s5JC_.js → toNumber-CbZ70FdN.js} +2 -2
- package/dist/{toString-Ckpb50uw.js → toString-DbIAWQpF.js} +2 -2
- package/dist/{tooltip-CL8m4f9y.js → tooltip-SPkubVH3.js} +3 -3
- package/dist/{treemap-GDKQZRPO-DRxfDG65.js → treemap-GDKQZRPO-CkR-5ai2.js} +2 -2
- package/dist/{types-BwnzGcE4.js → types-Dzga1074.js} +519 -408
- package/dist/{uniq-cCc07Q8K.js → uniq-H2E5nMLq.js} +1 -1
- package/dist/{useAsyncData-B4hMFGnF.js → useAsyncData-BlSPOmJU.js} +1 -1
- package/dist/{useDeepCompareMemoize-DuPhOXzr.js → useDeepCompareMemoize-CpGehmfj.js} +5 -5
- package/dist/{useIframeCapabilities-CAt6D2EI.js → useIframeCapabilities-DFGZKWkO.js} +1 -1
- package/dist/{useTheme-BNYQnvu-.js → useTheme-BAtPEkUJ.js} +4 -4
- package/dist/{vega-component-DouPy8AI.js → vega-component-0KINBNtd.js} +10 -10
- package/dist/{xychartDiagram-PRI3JC2R-rEm_SIsC.js → xychartDiagram-PRI3JC2R-XO8FiQjU.js} +5 -5
- package/package.json +9 -9
- package/src/__mocks__/common.ts +41 -8
- package/src/__mocks__/requests.ts +1 -0
- package/src/components/app-config/ai-config.tsx +10 -0
- package/src/components/chat/__tests__/useFileState.test.tsx +2 -3
- package/src/components/chat/acp/__tests__/context-utils.test.ts +2 -6
- package/src/components/datasources/components.tsx +3 -6
- package/src/components/datasources/datasources.tsx +8 -21
- package/src/components/editor/__tests__/data-attributes.test.tsx +2 -11
- package/src/components/editor/actions/types.ts +6 -1
- package/src/components/editor/actions/useNotebookActions.tsx +50 -13
- package/src/components/editor/chrome/types.ts +17 -0
- package/src/components/editor/controls/command-palette.tsx +7 -0
- package/src/components/editor/controls/keyboard-shortcuts.tsx +3 -1
- package/src/components/editor/file-tree/__tests__/requesting-tree.test.ts +2 -3
- package/src/components/editor/file-tree/file-explorer.tsx +48 -62
- package/src/components/editor/file-tree/file-icons.tsx +132 -0
- package/src/components/editor/file-tree/file-viewer.tsx +1 -1
- package/src/components/editor/file-tree/tree-actions.tsx +107 -0
- package/src/components/editor/file-tree/types.ts +2 -96
- package/src/components/editor/header/filename-input.tsx +4 -1
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +2 -4
- package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +2 -12
- package/src/components/icons/marimo-icons.tsx +2 -2
- package/src/components/pages/home-page.tsx +5 -5
- package/src/components/storage/__tests__/storage-snippets.test.ts +253 -0
- package/src/components/storage/components.tsx +0 -38
- package/src/components/storage/storage-file-viewer.tsx +1 -1
- package/src/components/storage/storage-inspector.tsx +65 -50
- package/src/components/storage/storage-snippets.ts +67 -0
- package/src/components/ui/command.tsx +2 -0
- package/src/components/ui/links.tsx +1 -0
- package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +206 -0
- package/src/core/ai/tools/run-cells-tool.ts +75 -40
- package/src/core/cells/__tests__/cells.test.ts +62 -0
- package/src/core/cells/__tests__/session.test.ts +2 -7
- package/src/core/cells/cells.ts +25 -3
- package/src/core/codemirror/compat/__tests__/jupyter.test.ts +2 -3
- package/src/core/codemirror/markdown/__tests__/commands.test.ts +2 -3
- package/src/core/export/__tests__/hooks.test.ts +3 -10
- package/src/core/hotkeys/__tests__/hotkeys.test.ts +64 -1
- package/src/core/hotkeys/hotkeys.ts +29 -3
- package/src/core/islands/bridge.ts +1 -0
- package/src/core/network/__tests__/requests-network.test.ts +17 -0
- package/src/core/network/requests-lazy.ts +1 -0
- package/src/core/network/requests-network.ts +9 -0
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.tsx +1 -0
- package/src/core/network/types.ts +1 -0
- package/src/core/runtime/__tests__/runtime.test.ts +2 -8
- package/src/core/storage/__tests__/state.test.ts +1 -0
- package/src/core/wasm/bridge.ts +1 -0
- package/src/core/websocket/useMarimoKernelConnection.tsx +2 -0
- package/src/plugins/impl/FileBrowserPlugin.tsx +4 -4
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +2 -11
- package/src/plugins/impl/__tests__/DropdownPlugin.test.tsx +2 -11
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +309 -0
- package/src/plugins/impl/mpl-interactive/__tests__/mpl-websocket-shim.test.ts +110 -0
- package/src/plugins/impl/mpl-interactive/mpl-websocket-shim.ts +57 -0
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +8 -2
- package/src/plugins/plugins.ts +2 -0
- package/src/utils/__tests__/download.test.tsx +12 -14
- package/src/utils/__tests__/filenames.test.ts +7 -0
- package/src/utils/__tests__/smartMatch.test.ts +61 -0
- package/src/utils/filenames.ts +3 -0
- package/src/utils/smartMatch.ts +62 -0
- package/dist/_baseProperty-D1nWkRMz.js +0 -93
- package/dist/dist-BAeGo2rp.js +0 -5
- package/dist/dist-BqwCMSEa.js +0 -5
- package/dist/dist-Bum8FwTO.js +0 -6
- package/dist/dist-C0YiOwt_.js +0 -5
- package/dist/dist-C2uPv4iU.js +0 -5
- package/dist/dist-C5hOLsJN.js +0 -8
- package/dist/dist-C9NIAKMs.js +0 -8
- package/dist/dist-CCrzTtvk.js +0 -5
- package/dist/dist-CFS9i1rS.js +0 -8
- package/dist/dist-CyHZuhPH.js +0 -5
- package/dist/dist-CzcjWdIk.js +0 -6
- package/dist/dist-DaYyUSNC.js +0 -5
- package/dist/dist-DpDcJYNh.js +0 -8
- package/dist/dist-U_BfxcPn.js +0 -5
- package/dist/merge-CGQkMGzr.js +0 -51
- package/dist/reduce-BXFHs7IQ.js +0 -268
|
@@ -59,6 +59,8 @@ export interface PanelDescriptor {
|
|
|
59
59
|
defaultSection: PanelSection;
|
|
60
60
|
/** Capability required for this panel to be visible. If the capability is false, the panel is hidden. */
|
|
61
61
|
requiredCapability?: keyof Capabilities;
|
|
62
|
+
/** Additional search keywords for the command palette */
|
|
63
|
+
additionalKeywords?: string[];
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
/**
|
|
@@ -73,6 +75,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
73
75
|
label: "Files",
|
|
74
76
|
tooltip: "View files",
|
|
75
77
|
defaultSection: "sidebar",
|
|
78
|
+
additionalKeywords: ["explorer", "browser", "directory"],
|
|
76
79
|
},
|
|
77
80
|
{
|
|
78
81
|
type: "variables",
|
|
@@ -80,6 +83,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
80
83
|
label: "Variables",
|
|
81
84
|
tooltip: "Explore variables and data sources",
|
|
82
85
|
defaultSection: "sidebar",
|
|
86
|
+
additionalKeywords: ["state", "scope", "inspector"],
|
|
83
87
|
},
|
|
84
88
|
{
|
|
85
89
|
type: "packages",
|
|
@@ -87,6 +91,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
87
91
|
label: "Packages",
|
|
88
92
|
tooltip: "Manage packages",
|
|
89
93
|
defaultSection: "sidebar",
|
|
94
|
+
additionalKeywords: ["dependencies", "pip", "install"],
|
|
90
95
|
},
|
|
91
96
|
{
|
|
92
97
|
type: "ai",
|
|
@@ -94,6 +99,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
94
99
|
label: "AI",
|
|
95
100
|
tooltip: "Chat & Agents",
|
|
96
101
|
defaultSection: "sidebar",
|
|
102
|
+
additionalKeywords: ["chat", "copilot", "assistant"],
|
|
97
103
|
},
|
|
98
104
|
{
|
|
99
105
|
type: "outline",
|
|
@@ -101,6 +107,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
101
107
|
label: "Outline",
|
|
102
108
|
tooltip: "View outline",
|
|
103
109
|
defaultSection: "sidebar",
|
|
110
|
+
additionalKeywords: ["toc", "structure", "headings"],
|
|
104
111
|
},
|
|
105
112
|
{
|
|
106
113
|
type: "documentation",
|
|
@@ -108,6 +115,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
108
115
|
label: "Docs",
|
|
109
116
|
tooltip: "View live docs",
|
|
110
117
|
defaultSection: "sidebar",
|
|
118
|
+
additionalKeywords: ["reference", "api"],
|
|
111
119
|
},
|
|
112
120
|
{
|
|
113
121
|
type: "dependencies",
|
|
@@ -115,6 +123,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
115
123
|
label: "Dependencies",
|
|
116
124
|
tooltip: "Explore dependencies",
|
|
117
125
|
defaultSection: "sidebar",
|
|
126
|
+
additionalKeywords: ["graph", "imports"],
|
|
118
127
|
},
|
|
119
128
|
// Developer panel defaults
|
|
120
129
|
{
|
|
@@ -123,6 +132,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
123
132
|
label: "Errors",
|
|
124
133
|
tooltip: "View errors",
|
|
125
134
|
defaultSection: "developer-panel",
|
|
135
|
+
additionalKeywords: ["exceptions", "problems", "diagnostics"],
|
|
126
136
|
},
|
|
127
137
|
{
|
|
128
138
|
type: "scratchpad",
|
|
@@ -130,6 +140,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
130
140
|
label: "Scratchpad",
|
|
131
141
|
tooltip: "Scratchpad",
|
|
132
142
|
defaultSection: "developer-panel",
|
|
143
|
+
additionalKeywords: ["scratch", "draft", "playground"],
|
|
133
144
|
},
|
|
134
145
|
{
|
|
135
146
|
type: "tracing",
|
|
@@ -137,6 +148,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
137
148
|
label: "Tracing",
|
|
138
149
|
tooltip: "View tracing",
|
|
139
150
|
defaultSection: "developer-panel",
|
|
151
|
+
additionalKeywords: ["profiling", "performance"],
|
|
140
152
|
},
|
|
141
153
|
{
|
|
142
154
|
type: "secrets",
|
|
@@ -145,6 +157,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
145
157
|
tooltip: "Manage secrets",
|
|
146
158
|
defaultSection: "developer-panel",
|
|
147
159
|
hidden: isWasm(),
|
|
160
|
+
additionalKeywords: ["env", "environment", "keys", "credentials"],
|
|
148
161
|
},
|
|
149
162
|
{
|
|
150
163
|
type: "logs",
|
|
@@ -152,6 +165,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
152
165
|
label: "Logs",
|
|
153
166
|
tooltip: "View logs",
|
|
154
167
|
defaultSection: "developer-panel",
|
|
168
|
+
additionalKeywords: ["console", "stdout"],
|
|
155
169
|
},
|
|
156
170
|
{
|
|
157
171
|
type: "terminal",
|
|
@@ -161,6 +175,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
161
175
|
hidden: isWasm(),
|
|
162
176
|
defaultSection: "developer-panel",
|
|
163
177
|
requiredCapability: "terminal",
|
|
178
|
+
additionalKeywords: ["shell", "console", "bash", "command"],
|
|
164
179
|
},
|
|
165
180
|
{
|
|
166
181
|
type: "snippets",
|
|
@@ -168,6 +183,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
168
183
|
label: "Snippets",
|
|
169
184
|
tooltip: "Snippets",
|
|
170
185
|
defaultSection: "developer-panel",
|
|
186
|
+
additionalKeywords: ["templates", "examples"],
|
|
171
187
|
},
|
|
172
188
|
{
|
|
173
189
|
type: "cache",
|
|
@@ -176,6 +192,7 @@ export const PANELS: PanelDescriptor[] = [
|
|
|
176
192
|
tooltip: "View cache",
|
|
177
193
|
defaultSection: "developer-panel",
|
|
178
194
|
hidden: !getFeatureFlag("cache_panel"),
|
|
195
|
+
additionalKeywords: ["memory", "memoize"],
|
|
179
196
|
},
|
|
180
197
|
];
|
|
181
198
|
|
|
@@ -78,6 +78,7 @@ const CommandPalette = () => {
|
|
|
78
78
|
return (
|
|
79
79
|
<CommandItem
|
|
80
80
|
disabled={props.disabled}
|
|
81
|
+
keywords={hotkey.additionalKeywords}
|
|
81
82
|
onSelect={() => {
|
|
82
83
|
addRecentCommand(shortcut);
|
|
83
84
|
// Close first and then run the action, so the dialog doesn't steal focus
|
|
@@ -105,15 +106,18 @@ const CommandPalette = () => {
|
|
|
105
106
|
handle,
|
|
106
107
|
props = {},
|
|
107
108
|
hotkey,
|
|
109
|
+
additionalKeywords,
|
|
108
110
|
}: {
|
|
109
111
|
label: string;
|
|
110
112
|
handle: () => void;
|
|
111
113
|
props?: { disabled?: boolean; tooltip?: React.ReactNode };
|
|
112
114
|
hotkey?: HotkeyAction;
|
|
115
|
+
additionalKeywords?: string[];
|
|
113
116
|
}) => {
|
|
114
117
|
return (
|
|
115
118
|
<CommandItem
|
|
116
119
|
disabled={props.disabled}
|
|
120
|
+
keywords={additionalKeywords}
|
|
117
121
|
onSelect={() => {
|
|
118
122
|
addRecentCommand(label);
|
|
119
123
|
setOpen(false);
|
|
@@ -163,6 +167,7 @@ const CommandPalette = () => {
|
|
|
163
167
|
disabled: action.disabled,
|
|
164
168
|
tooltip: action.tooltip,
|
|
165
169
|
},
|
|
170
|
+
additionalKeywords: action.additionalKeywords,
|
|
166
171
|
});
|
|
167
172
|
}
|
|
168
173
|
return null;
|
|
@@ -190,6 +195,7 @@ const CommandPalette = () => {
|
|
|
190
195
|
label: action.label,
|
|
191
196
|
handle: action.handleHeadless || action.handle,
|
|
192
197
|
props: { disabled: action.disabled, tooltip: action.tooltip },
|
|
198
|
+
additionalKeywords: action.additionalKeywords,
|
|
193
199
|
});
|
|
194
200
|
})}
|
|
195
201
|
{cellActions.map((action) => {
|
|
@@ -200,6 +206,7 @@ const CommandPalette = () => {
|
|
|
200
206
|
label: `Cell > ${action.label}`,
|
|
201
207
|
handle: action.handleHeadless || action.handle,
|
|
202
208
|
props: { disabled: action.disabled, tooltip: action.tooltip },
|
|
209
|
+
additionalKeywords: action.additionalKeywords,
|
|
203
210
|
});
|
|
204
211
|
})}
|
|
205
212
|
</CommandGroup>
|
|
@@ -174,7 +174,9 @@ export const KeyboardShortcuts: React.FC = () => {
|
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
// Single character keys are always lowercase (e.g. "a", "b", "c")
|
|
178
|
+
// But we should preserve the original case for other keys (e.g. "Enter", "Escape")
|
|
179
|
+
let key = e.key.length === 1 ? e.key.toLowerCase() : e.key;
|
|
178
180
|
// Handle edge cases
|
|
179
181
|
if (e.key === " ") {
|
|
180
182
|
key = "Space";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
3
|
+
import { MockModules } from "@/__mocks__/common";
|
|
3
4
|
import { toast } from "@/components/ui/use-toast";
|
|
4
5
|
import type { FilePath } from "@/utils/paths";
|
|
5
6
|
import { RequestingTree } from "../requesting-tree";
|
|
@@ -9,9 +10,7 @@ const sendCreateFileOrFolder = vi.fn();
|
|
|
9
10
|
const sendDeleteFileOrFolder = vi.fn();
|
|
10
11
|
const sendRenameFileOrFolder = vi.fn();
|
|
11
12
|
|
|
12
|
-
vi.mock("@/components/ui/use-toast", () => (
|
|
13
|
-
toast: vi.fn(),
|
|
14
|
-
}));
|
|
13
|
+
vi.mock("@/components/ui/use-toast", () => MockModules.toast());
|
|
15
14
|
|
|
16
15
|
describe("RequestingTree", () => {
|
|
17
16
|
let requestingTree: RequestingTree;
|
|
@@ -6,8 +6,6 @@ import {
|
|
|
6
6
|
ArrowLeftIcon,
|
|
7
7
|
BetweenHorizontalStartIcon,
|
|
8
8
|
BracesIcon,
|
|
9
|
-
ChevronDownIcon,
|
|
10
|
-
ChevronRightIcon,
|
|
11
9
|
CopyIcon,
|
|
12
10
|
CopyMinusIcon,
|
|
13
11
|
DownloadIcon,
|
|
@@ -17,9 +15,7 @@ import {
|
|
|
17
15
|
FilePlus2Icon,
|
|
18
16
|
FolderPlusIcon,
|
|
19
17
|
ListTreeIcon,
|
|
20
|
-
MoreVerticalIcon,
|
|
21
18
|
PlaySquareIcon,
|
|
22
|
-
RefreshCcwIcon,
|
|
23
19
|
Trash2Icon,
|
|
24
20
|
UploadIcon,
|
|
25
21
|
ViewIcon,
|
|
@@ -32,6 +28,18 @@ import {
|
|
|
32
28
|
type TreeApi,
|
|
33
29
|
} from "react-arborist";
|
|
34
30
|
import useEvent from "react-use-event-hook";
|
|
31
|
+
import {
|
|
32
|
+
FILE_ICON,
|
|
33
|
+
FILE_ICON_COLOR,
|
|
34
|
+
type FileIconType,
|
|
35
|
+
guessFileIconType,
|
|
36
|
+
} from "@/components/editor/file-tree/file-icons";
|
|
37
|
+
import {
|
|
38
|
+
MENU_ITEM_ICON_CLASS,
|
|
39
|
+
MoreActionsButton,
|
|
40
|
+
RefreshIconButton,
|
|
41
|
+
TreeChevron,
|
|
42
|
+
} from "@/components/editor/file-tree/tree-actions";
|
|
35
43
|
import { MarimoIcon, MarimoPlusIcon } from "@/components/icons/marimo-icons";
|
|
36
44
|
import { Spinner } from "@/components/icons/spinner";
|
|
37
45
|
import { useImperativeModal } from "@/components/modal/ImperativeModal";
|
|
@@ -65,12 +73,7 @@ import { useTreeDndManager } from "./dnd-wrapper";
|
|
|
65
73
|
import { FileViewer } from "./file-viewer";
|
|
66
74
|
import type { RequestingTree } from "./requesting-tree";
|
|
67
75
|
import { openStateAtom, treeAtom } from "./state";
|
|
68
|
-
import {
|
|
69
|
-
FILE_TYPE_ICONS,
|
|
70
|
-
type FileType,
|
|
71
|
-
guessFileType,
|
|
72
|
-
PYTHON_CODE_FOR_FILE_TYPE,
|
|
73
|
-
} from "./types";
|
|
76
|
+
import { PYTHON_CODE_FOR_FILE_TYPE } from "./types";
|
|
74
77
|
import { useFileExplorerUpload } from "./upload";
|
|
75
78
|
|
|
76
79
|
const hiddenFilesState = atomWithStorage(
|
|
@@ -102,7 +105,10 @@ export const FileExplorer: React.FC<{
|
|
|
102
105
|
const { isPending, error } = useAsyncData(() => tree.initialize(setData), []);
|
|
103
106
|
|
|
104
107
|
const handleRefresh = useEvent(() => {
|
|
105
|
-
|
|
108
|
+
// Return the promise so callers can await refresh completion
|
|
109
|
+
return tree.refreshAll(
|
|
110
|
+
Object.keys(openState).filter((id) => openState[id]),
|
|
111
|
+
);
|
|
106
112
|
});
|
|
107
113
|
|
|
108
114
|
const handleHiddenFilesToggle = useEvent(() => {
|
|
@@ -322,16 +328,10 @@ const Toolbar = ({
|
|
|
322
328
|
</button>
|
|
323
329
|
</Tooltip>
|
|
324
330
|
<input {...getInputProps({})} type="file" />
|
|
325
|
-
<
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
variant="text"
|
|
330
|
-
size="xs"
|
|
331
|
-
>
|
|
332
|
-
<RefreshCcwIcon size={16} />
|
|
333
|
-
</Button>
|
|
334
|
-
</Tooltip>
|
|
331
|
+
<RefreshIconButton
|
|
332
|
+
data-testid="file-explorer-refresh-button"
|
|
333
|
+
onClick={onRefresh}
|
|
334
|
+
/>
|
|
335
335
|
<Tooltip content="Toggle hidden files">
|
|
336
336
|
<Button
|
|
337
337
|
data-testid="file-explorer-hidden-files-button"
|
|
@@ -421,11 +421,11 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
421
421
|
useRequestClient();
|
|
422
422
|
const disableFileDownloads = useAtomValue(disableFileDownloadsAtom);
|
|
423
423
|
|
|
424
|
-
const fileType:
|
|
424
|
+
const fileType: FileIconType = node.data.isDirectory
|
|
425
425
|
? "directory"
|
|
426
|
-
:
|
|
426
|
+
: guessFileIconType(node.data.name);
|
|
427
427
|
|
|
428
|
-
const Icon =
|
|
428
|
+
const Icon = FILE_ICON[fileType];
|
|
429
429
|
const { openConfirm, openPrompt } = useImperativeModal();
|
|
430
430
|
const { createNewCell } = useCellActions();
|
|
431
431
|
const lastFocusedCellId = useLastFocusedCellId();
|
|
@@ -534,11 +534,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
534
534
|
});
|
|
535
535
|
|
|
536
536
|
const renderActions = () => {
|
|
537
|
-
const
|
|
538
|
-
size: 14,
|
|
539
|
-
strokeWidth: 1.5,
|
|
540
|
-
className: "mr-2",
|
|
541
|
-
};
|
|
537
|
+
const ic = MENU_ITEM_ICON_CLASS;
|
|
542
538
|
return (
|
|
543
539
|
<DropdownMenuContent
|
|
544
540
|
align="end"
|
|
@@ -548,7 +544,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
548
544
|
>
|
|
549
545
|
{!node.data.isDirectory && (
|
|
550
546
|
<DropdownMenuItem onSelect={() => node.select()}>
|
|
551
|
-
<ViewIcon {
|
|
547
|
+
<ViewIcon className={ic} />
|
|
552
548
|
Open file
|
|
553
549
|
</DropdownMenuItem>
|
|
554
550
|
)}
|
|
@@ -558,34 +554,34 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
558
554
|
openFile({ path: node.data.path });
|
|
559
555
|
}}
|
|
560
556
|
>
|
|
561
|
-
<ExternalLinkIcon {
|
|
557
|
+
<ExternalLinkIcon className={ic} />
|
|
562
558
|
Open file in external editor
|
|
563
559
|
</DropdownMenuItem>
|
|
564
560
|
)}
|
|
565
561
|
{node.data.isDirectory && (
|
|
566
562
|
<>
|
|
567
563
|
<DropdownMenuItem onSelect={() => handleCreateNotebook()}>
|
|
568
|
-
<MarimoPlusIcon {
|
|
564
|
+
<MarimoPlusIcon className={ic} />
|
|
569
565
|
Create notebook
|
|
570
566
|
</DropdownMenuItem>
|
|
571
567
|
<DropdownMenuItem onSelect={() => handleCreateFile()}>
|
|
572
|
-
<FilePlus2Icon {
|
|
568
|
+
<FilePlus2Icon className={ic} />
|
|
573
569
|
Create file
|
|
574
570
|
</DropdownMenuItem>
|
|
575
571
|
<DropdownMenuItem onSelect={() => handleCreateFolder()}>
|
|
576
|
-
<FolderPlusIcon {
|
|
572
|
+
<FolderPlusIcon className={ic} />
|
|
577
573
|
Create folder
|
|
578
574
|
</DropdownMenuItem>
|
|
579
575
|
<DropdownMenuSeparator />
|
|
580
576
|
</>
|
|
581
577
|
)}
|
|
582
578
|
<DropdownMenuItem onSelect={() => node.edit()}>
|
|
583
|
-
<Edit3Icon {
|
|
579
|
+
<Edit3Icon className={ic} />
|
|
584
580
|
Rename
|
|
585
581
|
</DropdownMenuItem>
|
|
586
582
|
{!node.data.isDirectory && (
|
|
587
583
|
<DropdownMenuItem onSelect={handleDuplicate}>
|
|
588
|
-
<CopyIcon {
|
|
584
|
+
<CopyIcon className={ic} />
|
|
589
585
|
Duplicate
|
|
590
586
|
</DropdownMenuItem>
|
|
591
587
|
)}
|
|
@@ -595,7 +591,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
595
591
|
toast({ title: "Copied to clipboard" });
|
|
596
592
|
}}
|
|
597
593
|
>
|
|
598
|
-
<ListTreeIcon {
|
|
594
|
+
<ListTreeIcon className={ic} />
|
|
599
595
|
Copy path
|
|
600
596
|
</DropdownMenuItem>
|
|
601
597
|
{tree && (
|
|
@@ -607,7 +603,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
607
603
|
toast({ title: "Copied to clipboard" });
|
|
608
604
|
}}
|
|
609
605
|
>
|
|
610
|
-
<ListTreeIcon {
|
|
606
|
+
<ListTreeIcon className={ic} />
|
|
611
607
|
Copy relative path
|
|
612
608
|
</DropdownMenuItem>
|
|
613
609
|
)}
|
|
@@ -620,7 +616,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
620
616
|
handleInsertCode(pythonCode);
|
|
621
617
|
}}
|
|
622
618
|
>
|
|
623
|
-
<BetweenHorizontalStartIcon {
|
|
619
|
+
<BetweenHorizontalStartIcon className={ic} />
|
|
624
620
|
Insert snippet for reading file
|
|
625
621
|
</DropdownMenuItem>
|
|
626
622
|
<DropdownMenuItem
|
|
@@ -635,7 +631,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
635
631
|
await copyToClipboard(pythonCode);
|
|
636
632
|
}}
|
|
637
633
|
>
|
|
638
|
-
<BracesIcon {
|
|
634
|
+
<BracesIcon className={ic} />
|
|
639
635
|
Copy snippet for reading file
|
|
640
636
|
</DropdownMenuItem>
|
|
641
637
|
{/* Not shown in WASM */}
|
|
@@ -643,7 +639,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
643
639
|
<>
|
|
644
640
|
<DropdownMenuSeparator />
|
|
645
641
|
<DropdownMenuItem onSelect={handleOpenMarimoFile}>
|
|
646
|
-
<PlaySquareIcon {
|
|
642
|
+
<PlaySquareIcon className={ic} />
|
|
647
643
|
Open notebook
|
|
648
644
|
</DropdownMenuItem>
|
|
649
645
|
</>
|
|
@@ -658,14 +654,14 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
658
654
|
downloadBlob(new Blob([contents]), node.data.name);
|
|
659
655
|
}}
|
|
660
656
|
>
|
|
661
|
-
<DownloadIcon {
|
|
657
|
+
<DownloadIcon className={ic} />
|
|
662
658
|
Download
|
|
663
659
|
</DropdownMenuItem>
|
|
664
660
|
<DropdownMenuSeparator />
|
|
665
661
|
</>
|
|
666
662
|
)}
|
|
667
663
|
<DropdownMenuItem onSelect={handleDeleteFile} variant="danger">
|
|
668
|
-
<Trash2Icon {
|
|
664
|
+
<Trash2Icon className={ic} />
|
|
669
665
|
Delete
|
|
670
666
|
</DropdownMenuItem>
|
|
671
667
|
</DropdownMenuContent>
|
|
@@ -699,7 +695,10 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
699
695
|
{node.data.isMarimoFile ? (
|
|
700
696
|
<MarimoIcon className="w-5 h-5 shrink-0 mr-2" strokeWidth={1.5} />
|
|
701
697
|
) : (
|
|
702
|
-
<Icon
|
|
698
|
+
<Icon
|
|
699
|
+
className={cn("w-5 h-5 shrink-0 mr-2", FILE_ICON_COLOR[fileType])}
|
|
700
|
+
strokeWidth={1.5}
|
|
701
|
+
/>
|
|
703
702
|
)}
|
|
704
703
|
{node.isEditing ? (
|
|
705
704
|
<Edit node={node} />
|
|
@@ -712,19 +711,10 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
712
711
|
tabIndex={-1}
|
|
713
712
|
onClick={(e) => e.stopPropagation()}
|
|
714
713
|
>
|
|
715
|
-
<
|
|
714
|
+
<MoreActionsButton
|
|
716
715
|
data-testid="file-explorer-more-button"
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
size="xs"
|
|
720
|
-
className="mb-0"
|
|
721
|
-
aria-label="More options"
|
|
722
|
-
>
|
|
723
|
-
<MoreVerticalIcon
|
|
724
|
-
strokeWidth={2}
|
|
725
|
-
className="w-5 h-5 hidden group-hover:block"
|
|
726
|
-
/>
|
|
727
|
-
</Button>
|
|
716
|
+
iconClassName="w-5 h-5"
|
|
717
|
+
/>
|
|
728
718
|
</DropdownMenuTrigger>
|
|
729
719
|
{renderActions()}
|
|
730
720
|
</DropdownMenu>
|
|
@@ -735,14 +725,10 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
735
725
|
|
|
736
726
|
const FolderArrow = ({ node }: { node: NodeApi<FileInfo> }) => {
|
|
737
727
|
if (!node.data.isDirectory) {
|
|
738
|
-
return <span className="w-
|
|
728
|
+
return <span className="w-4 h-4 shrink-0" />;
|
|
739
729
|
}
|
|
740
730
|
|
|
741
|
-
return node.isOpen
|
|
742
|
-
<ChevronDownIcon className="w-5 h-5 shrink-0" />
|
|
743
|
-
) : (
|
|
744
|
-
<ChevronRightIcon className="w-5 h-5 shrink-0" />
|
|
745
|
-
);
|
|
731
|
+
return <TreeChevron isExpanded={node.isOpen} className="w-4 h-4" />;
|
|
746
732
|
};
|
|
747
733
|
|
|
748
734
|
function openMarimoNotebook(
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
FileAudioIcon,
|
|
5
|
+
FileCodeIcon,
|
|
6
|
+
FileIcon,
|
|
7
|
+
FileJsonIcon,
|
|
8
|
+
FileSpreadsheetIcon,
|
|
9
|
+
FileTextIcon,
|
|
10
|
+
FileVideoIcon,
|
|
11
|
+
FolderArchiveIcon,
|
|
12
|
+
FolderIcon,
|
|
13
|
+
ImageIcon,
|
|
14
|
+
type LucideIcon,
|
|
15
|
+
} from "lucide-react";
|
|
16
|
+
import { cn } from "@/utils/cn";
|
|
17
|
+
|
|
18
|
+
export type FileIconType =
|
|
19
|
+
| "directory"
|
|
20
|
+
| "python"
|
|
21
|
+
| "code"
|
|
22
|
+
| "json"
|
|
23
|
+
| "text"
|
|
24
|
+
| "image"
|
|
25
|
+
| "audio"
|
|
26
|
+
| "video"
|
|
27
|
+
| "data"
|
|
28
|
+
| "pdf"
|
|
29
|
+
| "zip"
|
|
30
|
+
| "unknown";
|
|
31
|
+
|
|
32
|
+
const EXT_TO_TYPE: Record<string, FileIconType> = {
|
|
33
|
+
py: "python",
|
|
34
|
+
// Text / docs
|
|
35
|
+
txt: "text",
|
|
36
|
+
md: "text",
|
|
37
|
+
qmd: "text",
|
|
38
|
+
log: "text",
|
|
39
|
+
// Images
|
|
40
|
+
png: "image",
|
|
41
|
+
jpg: "image",
|
|
42
|
+
jpeg: "image",
|
|
43
|
+
gif: "image",
|
|
44
|
+
svg: "image",
|
|
45
|
+
webp: "image",
|
|
46
|
+
// Data / spreadsheets
|
|
47
|
+
csv: "data",
|
|
48
|
+
parquet: "data",
|
|
49
|
+
arrow: "data",
|
|
50
|
+
xlsx: "data",
|
|
51
|
+
// JSON
|
|
52
|
+
json: "json",
|
|
53
|
+
// Code
|
|
54
|
+
js: "code",
|
|
55
|
+
ts: "code",
|
|
56
|
+
tsx: "code",
|
|
57
|
+
html: "code",
|
|
58
|
+
css: "code",
|
|
59
|
+
toml: "code",
|
|
60
|
+
yaml: "code",
|
|
61
|
+
yml: "code",
|
|
62
|
+
wasm: "code",
|
|
63
|
+
// Audio
|
|
64
|
+
mp3: "audio",
|
|
65
|
+
m4a: "audio",
|
|
66
|
+
ogg: "audio",
|
|
67
|
+
wav: "audio",
|
|
68
|
+
// Video
|
|
69
|
+
mp4: "video",
|
|
70
|
+
m4v: "video",
|
|
71
|
+
mpeg: "video",
|
|
72
|
+
webm: "video",
|
|
73
|
+
mkv: "video",
|
|
74
|
+
// PDF
|
|
75
|
+
pdf: "pdf",
|
|
76
|
+
// Archives
|
|
77
|
+
zip: "zip",
|
|
78
|
+
tar: "zip",
|
|
79
|
+
gz: "zip",
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export function guessFileIconType(name: string): FileIconType {
|
|
83
|
+
const ext = name.split(".").pop()?.toLowerCase();
|
|
84
|
+
if (!ext) {
|
|
85
|
+
return "unknown";
|
|
86
|
+
}
|
|
87
|
+
return EXT_TO_TYPE[ext] ?? "unknown";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const FILE_ICON: Record<FileIconType, LucideIcon> = {
|
|
91
|
+
directory: FolderIcon,
|
|
92
|
+
python: FileCodeIcon,
|
|
93
|
+
code: FileCodeIcon,
|
|
94
|
+
json: FileJsonIcon,
|
|
95
|
+
text: FileTextIcon,
|
|
96
|
+
image: ImageIcon,
|
|
97
|
+
audio: FileAudioIcon,
|
|
98
|
+
video: FileVideoIcon,
|
|
99
|
+
data: FileSpreadsheetIcon,
|
|
100
|
+
pdf: FileTextIcon,
|
|
101
|
+
zip: FolderArchiveIcon,
|
|
102
|
+
unknown: FileIcon,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const FILE_ICON_COLOR: Record<FileIconType, string> = {
|
|
106
|
+
directory: "text-amber-500",
|
|
107
|
+
python: "text-blue-500",
|
|
108
|
+
code: "text-blue-500",
|
|
109
|
+
json: "text-blue-500",
|
|
110
|
+
text: "text-muted-foreground",
|
|
111
|
+
image: "text-purple-500",
|
|
112
|
+
audio: "text-orange-500",
|
|
113
|
+
video: "text-orange-500",
|
|
114
|
+
data: "text-green-500",
|
|
115
|
+
pdf: "text-red-500",
|
|
116
|
+
zip: "text-muted-foreground",
|
|
117
|
+
unknown: "text-muted-foreground",
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Render a colored file-type icon for a given filename.
|
|
122
|
+
* Pass `className` to control size (defaults to `h-3.5 w-3.5`).
|
|
123
|
+
*/
|
|
124
|
+
export function renderFileIcon(
|
|
125
|
+
name: string,
|
|
126
|
+
className?: string,
|
|
127
|
+
): React.ReactNode {
|
|
128
|
+
const type = guessFileIconType(name);
|
|
129
|
+
const Icon = FILE_ICON[type];
|
|
130
|
+
const color = FILE_ICON_COLOR[type];
|
|
131
|
+
return <Icon className={cn("h-3.5 w-3.5 shrink-0", color, className)} />;
|
|
132
|
+
}
|
|
@@ -166,7 +166,7 @@ export const FileViewer: React.FC<Props> = ({ file, onOpenNotebook }) => {
|
|
|
166
166
|
</Tooltip>
|
|
167
167
|
<Tooltip content={renderShortcut("global.save")}>
|
|
168
168
|
<Button
|
|
169
|
-
variant=
|
|
169
|
+
variant="text"
|
|
170
170
|
size="xs"
|
|
171
171
|
onClick={handleSaveFile}
|
|
172
172
|
disabled={internalValue === data.contents}
|