@marimo-team/islands 0.25.3-dev5 → 0.25.3-dev51
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-CNMliVzw.js → ConnectedDataExplorerComponent-Da5OoEUL.js} +14 -14
- package/dist/{ErrorBoundary-BiZWOrv4.js → ErrorBoundary-CbxCC2kk.js} +8 -8
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Bz3mrprX.js} +2 -2
- package/dist/any-language-editor-k2B8YI3Y.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-Cs5ujb9K.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/{button-CvjkwdSk.js → button-BxB3RDjN.js} +1 -1
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-BgR0osfN.js} +2 -2
- package/dist/{chat-ui-0lKdOoQ3.js → chat-ui-C1Gjgokv.js} +1103 -1103
- package/dist/{check-EDwSwP89.js → check-P35dc2dH.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-CcTSaxZt.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-DcJcjOaO.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-BVtDTjaF.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-BkDFkh8q.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-CfAt7HT5.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-CGEjNYa2.js} +2 -2
- package/dist/{code-visibility-CW5_8ZOI.js → code-visibility-DoZ9lxzx.js} +6 -6
- package/dist/{common-mzWw4FdI.js → common-D1PacyXO.js} +3112 -3015
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-CPoxUG7G.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-BW6NmfJi.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-CWg3CTuF.js} +1 -1
- package/dist/{data-grid-overlay-editor-CJmehSdc.js → data-grid-overlay-editor-B50UpkXd.js} +5 -5
- package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-BsSJJldB.js → diagram-S7CK7UJ4-BPxtoS-z.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-DA-vJdFL.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-D6bkR84S.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-m60g4cAT.js} +1 -1
- package/dist/{dialog-CEBFZNyc.js → dialog-C1PcpCqX.js} +3 -3
- package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
- package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-MG5hiCIa.js} +76 -76
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-CK99sho2.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-Bryq0tdE.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-Sl2FlSJ4.js} +2 -2
- package/dist/{error-entries-DSvFWT_M.js → error-entries-CMNtA8NK.js} +959 -959
- package/dist/{feedback-button-BcT1FBud.js → feedback-button-DqPqwryB.js} +29 -29
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-D-3aRpfS.js} +2 -2
- package/dist/{formats-CeOmU1MU.js → formats-6pLWWrY2.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-XckatD0j.js → glide-data-editor-BxMhUd3K.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Bt8_pBa2.js} +16 -16
- package/dist/{globals-jRrLCkrP.js → globals-DTJa_doJ.js} +3 -3
- package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
- package/dist/{html-to-image-B8s5SgGm.js → html-to-image-By72ALyI.js} +29 -29
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-s1C1kgfU.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-CCsRgolY.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-BrmxDlcc.js} +1 -1
- package/dist/{label-BDKF3Afc.js → label-BRnUC0NX.js} +2 -2
- package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
- package/dist/{loader-BQOfjTIJ.js → loader-Bm8cy3e8.js} +12 -12
- package/dist/main.js +2358 -2221
- package/dist/{mermaid-CHo49Yv-.js → mermaid-DKI0869I.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-641xJysF.js} +1 -1
- package/dist/{number-overlay-editor-pZx8dUDV.js → number-overlay-editor-Z_H6x5b-.js} +3 -3
- package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
- package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-keVUAUeS.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-DHktXPO_.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-CKRXyszb.js → process-output-D-OMW5sV.js} +4 -4
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-BVEF4OV_.js} +2 -2
- package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
- package/dist/{requirementDiagram-BXWQKSXE-a_MxGvxe.js → requirementDiagram-BXWQKSXE-CWo-UAKV.js} +1 -1
- package/dist/{reveal-component-79ez8-D5.js → reveal-component-tAB5K3QE.js} +10 -10
- package/dist/{select-BButFi-d.js → select-B0LRDH0g.js} +4 -4
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-CHQvLnq4.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-C-LRKGtT.js} +4 -4
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-BOJZgbUJ.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-C53XXdYH.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-D2o1gOtw.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-BHFzN1Wk.js} +2 -2
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-DfhRvAFi.js} +2 -2
- package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
- package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-rv7QUa46.js} +1 -1
- package/dist/{toDate-vIXljnsr.js → toDate-CjPuEPou.js} +21 -20
- package/dist/{toast-B9UMEi8u.js → toast-CFWpihJU.js} +4 -4
- package/dist/{tooltip-BO1REbqs.js → tooltip-CKO1pHJo.js} +2 -2
- package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-DBCITLeF.js} +1 -1
- package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-ChgNtdmE.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-c_yJtkAe.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-Bet7kSsI.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-BkdeVdXC.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-VVmz_24o.js} +3 -3
- package/dist/{useTheme-CRnjkku0.js → useTheme-DympCsQg.js} +5 -5
- package/dist/{vega-component-DTG6zxaY.js → vega-component-DnfQeoyt.js} +147 -147
- package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
- package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
- package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-D36Zk7t-.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-BLBolvyQ.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-CfH57l0v.js} +2 -2
- package/package.json +4 -4
- package/src/__tests__/fixtures/{pair-preview.ts → pair-config.ts} +3 -2
- package/src/__tests__/host-imports.test.ts +1 -0
- package/src/__tests__/mount.test.ts +8 -8
- package/src/components/app-config/ai-config.tsx +5 -1
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/chat-panel.tsx +3 -7
- package/src/components/chat/chat-utils.ts +4 -8
- package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +417 -6
- package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
- package/src/components/data-table/columns.tsx +2 -1
- package/src/components/data-table/context-menu.tsx +36 -20
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +263 -161
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +2 -2
- package/src/components/data-table/schemas.ts +14 -36
- package/src/components/editor/Output.tsx +5 -1
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +80 -252
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +186 -34
- package/src/components/editor/actions/pair-with-agent-commands.ts +42 -51
- package/src/components/editor/actions/pair-with-agent-modal.tsx +96 -36
- package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
- package/src/components/editor/cell/CreateCellButton.tsx +8 -10
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +1 -1
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +277 -78
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +196 -41
- package/src/components/editor/connections/components.tsx +1 -1
- package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
- package/src/components/editor/controls/command-palette.tsx +22 -10
- package/src/components/editor/dynamic-favicon.tsx +21 -40
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +139 -36
- package/src/components/editor/errors/send-error-report-button.tsx +10 -7
- package/src/components/editor/file-tree/file-viewer.tsx +4 -2
- package/src/components/editor/output/MarimoTracebackOutput.tsx +28 -22
- package/src/components/editor/output/console/ConsoleOutput.tsx +8 -18
- package/src/components/pages/home-page.tsx +4 -4
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/tracing/tracing.tsx +2 -2
- package/src/core/attachments/__tests__/toast.test.tsx +58 -0
- package/src/core/attachments/state.ts +5 -8
- package/src/core/attachments/toast.ts +15 -0
- package/src/core/cells/__tests__/error-report.test.ts +53 -3
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +18 -3
- package/src/core/cells/cells.ts +2 -1
- package/src/core/cells/error-report.ts +14 -6
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +19 -1
- package/src/core/config/pair.ts +5 -3
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +4 -4
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/edit-app.tsx +2 -2
- package/src/core/host/AGENTS.md +11 -2
- package/src/core/host/__tests__/attachments.test.ts +56 -0
- package/src/core/host/__tests__/document.test.ts +126 -0
- package/src/core/host/__tests__/events.test.ts +49 -0
- package/src/core/host/__tests__/fixtures.ts +41 -0
- package/src/core/host/__tests__/notebook-client.test.ts +496 -0
- package/src/core/host/connection.ts +81 -0
- package/src/core/host/events.ts +68 -0
- package/src/core/host/notebook-client.ts +316 -0
- package/src/core/host/resources/attachments.ts +19 -0
- package/src/core/host/resources/document.ts +101 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +0 -26
- package/src/core/islands/bootstrap.ts +0 -1
- package/src/core/network/connection.ts +4 -2
- package/src/core/run-app.tsx +2 -2
- package/src/core/runtime/__tests__/runtime.test.ts +5 -12
- package/src/core/runtime/runtime.ts +5 -5
- package/src/core/static/files.ts +2 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts} +15 -17
- package/src/core/websocket/__tests__/{useWebSocket.test.ts → createConnectionTransport.test.ts} +1 -1
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +149 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.hook.test.tsx → useNotebookSession.hook.test.tsx} +168 -253
- package/src/core/websocket/connection-state.ts +70 -0
- package/src/core/websocket/state.ts +7 -0
- package/src/core/websocket/transports/__tests__/sse.test.ts +18 -4
- package/src/core/websocket/transports/create.ts +31 -0
- package/src/core/websocket/transports/sse.ts +14 -2
- package/src/core/websocket/transports/transport.ts +12 -23
- package/src/core/websocket/types.ts +9 -39
- package/src/core/websocket/useNotebookClient.ts +78 -0
- package/src/core/websocket/{useMarimoKernelConnection.tsx → useNotebookSession.tsx} +53 -233
- package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
- package/src/hooks/useAsyncData.ts +3 -3
- package/src/hooks/useDataSourceDiscovery.ts +6 -4
- package/src/hooks/useElapsedTime.ts +3 -3
- package/src/hooks/useInputHistory.ts +4 -7
- package/src/hooks/useResizeObserver.ts +4 -7
- package/src/mount.tsx +3 -3
- package/src/plugins/core/registerReactComponent.tsx +1 -1
- package/src/plugins/impl/DropdownPlugin.tsx +2 -6
- package/src/plugins/impl/FormPlugin.tsx +1 -1
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +84 -0
- package/src/plugins/impl/anywidget/__tests__/registry.test.ts +2 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/runtime.ts +21 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
- package/src/plugins/impl/code/any-language-editor.tsx +2 -2
- package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
- package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
- package/src/plugins/impl/panel/PanelPlugin.tsx +15 -16
- package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
- package/src/plugins/impl/panel/utils.ts +17 -0
- package/src/plugins/impl/vega/make-selectable.ts +3 -6
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/editor.stories.tsx +24 -17
- package/src/utils/__tests__/arrays.test.ts +35 -0
- package/src/utils/__tests__/numbers.test.ts +48 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +10 -0
- package/src/utils/numbers.ts +28 -17
- package/src/utils/objects.ts +3 -7
- package/src/utils/once.ts +19 -19
- package/dist/any-language-editor-DZ_YTVus.js +0 -76
- package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/protocol.ts +0 -1943
- package/src/core/websocket/useWebSocket.tsx +0 -88
|
@@ -17,18 +17,16 @@ import { Events } from "@/utils/events";
|
|
|
17
17
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
18
18
|
import { asRemoteURL, useRuntimeManager } from "@/core/runtime/config";
|
|
19
19
|
import { API } from "@/core/network/api";
|
|
20
|
-
import {
|
|
20
|
+
import { pairConfigAtom } from "@/core/config/pair";
|
|
21
21
|
import { stableSessionIdAtom } from "@/core/kernel/session";
|
|
22
22
|
import {
|
|
23
23
|
AGENT_LABELS,
|
|
24
24
|
AGENT_TABS,
|
|
25
25
|
type AgentTab,
|
|
26
26
|
type ConnectionInfo,
|
|
27
|
-
getFileFromURL,
|
|
28
27
|
getRawPrompt,
|
|
29
28
|
getTerminalCommand,
|
|
30
29
|
maskToken,
|
|
31
|
-
SKILL_INSTALL,
|
|
32
30
|
TERMINAL_TABS,
|
|
33
31
|
} from "./pair-with-agent-commands";
|
|
34
32
|
|
|
@@ -52,15 +50,64 @@ export const PairWithAgentModal: React.FC<{
|
|
|
52
50
|
}> = ({ onClose }) => {
|
|
53
51
|
const [activeTab, setActiveTab] = useState<AgentTab>("claude");
|
|
54
52
|
const runtimeManager = useRuntimeManager();
|
|
55
|
-
const
|
|
53
|
+
const config = useAtomValue(pairConfigAtom);
|
|
54
|
+
const hostEnabled = config?.hostEnabled ?? false;
|
|
56
55
|
const stableSessionId = useAtomValue(stableSessionIdAtom);
|
|
57
|
-
const
|
|
56
|
+
const [lookup, setLookup] = useState<
|
|
57
|
+
{
|
|
58
|
+
sessionId: string;
|
|
59
|
+
} & (
|
|
60
|
+
| { status: "ready"; notebookId: string | null }
|
|
61
|
+
| { status: "loading" | "error" }
|
|
62
|
+
)
|
|
63
|
+
>();
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!hostEnabled || !stableSessionId) {
|
|
66
|
+
setLookup(undefined);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const sessionId = stableSessionId;
|
|
70
|
+
setLookup({ sessionId, status: "loading" });
|
|
71
|
+
let cancelled = false;
|
|
72
|
+
API.get<Record<string, { session_id: string; notebook_id: string | null }>>(
|
|
73
|
+
"/sessions",
|
|
74
|
+
)
|
|
75
|
+
.then((sessions) => {
|
|
76
|
+
if (!cancelled) {
|
|
77
|
+
const session = Object.values(sessions).find(
|
|
78
|
+
(session) => session.session_id === sessionId,
|
|
79
|
+
);
|
|
80
|
+
setLookup(
|
|
81
|
+
session
|
|
82
|
+
? { sessionId, status: "ready", notebookId: session.notebook_id }
|
|
83
|
+
: { sessionId, status: "error" },
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
.catch(() => {
|
|
88
|
+
if (!cancelled) {
|
|
89
|
+
setLookup({ sessionId, status: "error" });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return () => {
|
|
93
|
+
cancelled = true;
|
|
94
|
+
};
|
|
95
|
+
}, [hostEnabled, stableSessionId]);
|
|
96
|
+
const currentLookup =
|
|
97
|
+
lookup?.sessionId === stableSessionId ? lookup : undefined;
|
|
98
|
+
const verified = !hostEnabled || currentLookup?.status === "ready";
|
|
99
|
+
const notebookId =
|
|
100
|
+
hostEnabled && currentLookup?.status === "ready"
|
|
101
|
+
? currentLookup.notebookId
|
|
102
|
+
: undefined;
|
|
103
|
+
const targetReady = Boolean(stableSessionId) && verified;
|
|
58
104
|
const authToken = useAuthToken();
|
|
59
105
|
const hasToken = Boolean(authToken);
|
|
60
106
|
const connection: ConnectionInfo = {
|
|
61
107
|
url: runtimeManager.httpURL.toString(),
|
|
62
|
-
|
|
63
|
-
session:
|
|
108
|
+
notebook: notebookId ?? undefined,
|
|
109
|
+
session:
|
|
110
|
+
targetReady && !notebookId ? (stableSessionId ?? undefined) : undefined,
|
|
64
111
|
};
|
|
65
112
|
|
|
66
113
|
return (
|
|
@@ -83,6 +130,13 @@ export const PairWithAgentModal: React.FC<{
|
|
|
83
130
|
</DialogHeader>
|
|
84
131
|
|
|
85
132
|
<div className="flex flex-col gap-4 py-2">
|
|
133
|
+
{!targetReady && (
|
|
134
|
+
<output className="text-sm text-muted-foreground">
|
|
135
|
+
{currentLookup?.status === "error"
|
|
136
|
+
? "Could not verify this notebook. Close this dialog and try again."
|
|
137
|
+
: "Waiting for the notebook connection…"}
|
|
138
|
+
</output>
|
|
139
|
+
)}
|
|
86
140
|
<Tabs
|
|
87
141
|
value={activeTab}
|
|
88
142
|
onValueChange={(v) => setActiveTab(v as AgentTab)}
|
|
@@ -101,30 +155,27 @@ export const PairWithAgentModal: React.FC<{
|
|
|
101
155
|
value={tab}
|
|
102
156
|
className="mt-4 flex flex-col gap-4"
|
|
103
157
|
>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<Step index={commandStep} title="Run in your terminal">
|
|
158
|
+
<Step
|
|
159
|
+
index={1}
|
|
160
|
+
title="Run in your terminal"
|
|
161
|
+
hint={
|
|
162
|
+
hostEnabled && tab === "opencode"
|
|
163
|
+
? "Agent connections require OpenCode 2.x."
|
|
164
|
+
: undefined
|
|
165
|
+
}
|
|
166
|
+
>
|
|
114
167
|
<CommandBlock
|
|
115
168
|
command={getTerminalCommand(
|
|
116
169
|
tab,
|
|
117
170
|
connection,
|
|
118
171
|
hasToken,
|
|
119
|
-
|
|
172
|
+
config,
|
|
120
173
|
)}
|
|
174
|
+
disabled={!targetReady}
|
|
121
175
|
/>
|
|
122
176
|
</Step>
|
|
123
177
|
{hasToken && authToken && (
|
|
124
|
-
<Step
|
|
125
|
-
index={commandStep + 1}
|
|
126
|
-
title="Paste when prompted for a token"
|
|
127
|
-
>
|
|
178
|
+
<Step index={2} title="Paste when prompted for a token">
|
|
128
179
|
<CommandBlock
|
|
129
180
|
command={authToken}
|
|
130
181
|
display={maskToken(authToken)}
|
|
@@ -136,17 +187,8 @@ export const PairWithAgentModal: React.FC<{
|
|
|
136
187
|
))}
|
|
137
188
|
|
|
138
189
|
<TabsContent value="prompt" className="mt-4 flex flex-col gap-4">
|
|
139
|
-
{!preview && (
|
|
140
|
-
<Step
|
|
141
|
-
index={1}
|
|
142
|
-
title="Make sure the marimo-pair skill is available to your agent"
|
|
143
|
-
hint="Skip if your agent already has it."
|
|
144
|
-
>
|
|
145
|
-
<CommandBlock command={SKILL_INSTALL} />
|
|
146
|
-
</Step>
|
|
147
|
-
)}
|
|
148
190
|
<Step
|
|
149
|
-
index={
|
|
191
|
+
index={1}
|
|
150
192
|
title="Copy this prompt into your agent"
|
|
151
193
|
hint={
|
|
152
194
|
hasToken
|
|
@@ -155,13 +197,14 @@ export const PairWithAgentModal: React.FC<{
|
|
|
155
197
|
}
|
|
156
198
|
>
|
|
157
199
|
<CommandBlock
|
|
158
|
-
command={getRawPrompt(connection, authToken,
|
|
200
|
+
command={getRawPrompt(connection, authToken, config)}
|
|
159
201
|
display={getRawPrompt(
|
|
160
202
|
connection,
|
|
161
203
|
authToken ? maskToken(authToken) : null,
|
|
162
|
-
|
|
204
|
+
config,
|
|
163
205
|
)}
|
|
164
206
|
multiline={true}
|
|
207
|
+
disabled={!targetReady}
|
|
165
208
|
/>
|
|
166
209
|
</Step>
|
|
167
210
|
</TabsContent>
|
|
@@ -199,11 +242,21 @@ const CommandBlock: React.FC<{
|
|
|
199
242
|
display?: string;
|
|
200
243
|
multiline?: boolean;
|
|
201
244
|
copyLabel?: string;
|
|
202
|
-
|
|
245
|
+
disabled?: boolean;
|
|
246
|
+
}> = ({
|
|
247
|
+
command,
|
|
248
|
+
display,
|
|
249
|
+
multiline = false,
|
|
250
|
+
copyLabel = "Copy command",
|
|
251
|
+
disabled = false,
|
|
252
|
+
}) => {
|
|
203
253
|
const [copied, setCopied] = useState(false);
|
|
204
254
|
|
|
205
255
|
const copy = Events.stopPropagation(async (e) => {
|
|
206
256
|
e.preventDefault();
|
|
257
|
+
if (disabled) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
207
260
|
await copyToClipboard(command);
|
|
208
261
|
setCopied(true);
|
|
209
262
|
setTimeout(() => setCopied(false), 2000);
|
|
@@ -218,6 +271,7 @@ const CommandBlock: React.FC<{
|
|
|
218
271
|
<Tooltip content="Copied!" open={copied}>
|
|
219
272
|
<Button
|
|
220
273
|
aria-label="Copy prompt"
|
|
274
|
+
disabled={disabled}
|
|
221
275
|
onClick={copy}
|
|
222
276
|
size="xs"
|
|
223
277
|
variant="ghost"
|
|
@@ -240,7 +294,13 @@ const CommandBlock: React.FC<{
|
|
|
240
294
|
{display ?? command}
|
|
241
295
|
</code>
|
|
242
296
|
<Tooltip content="Copied!" open={copied}>
|
|
243
|
-
<Button
|
|
297
|
+
<Button
|
|
298
|
+
aria-label={copyLabel}
|
|
299
|
+
onClick={copy}
|
|
300
|
+
size="xs"
|
|
301
|
+
variant="ghost"
|
|
302
|
+
disabled={disabled}
|
|
303
|
+
>
|
|
244
304
|
{copied ? (
|
|
245
305
|
<CheckIcon size={14} strokeWidth={1.5} />
|
|
246
306
|
) : (
|
|
@@ -106,9 +106,9 @@ export const AddCellWithAI: React.FC<{
|
|
|
106
106
|
const runtimeManager = useRuntimeManager();
|
|
107
107
|
|
|
108
108
|
const inputRef = useRef<ReactCodeMirrorRef>(null);
|
|
109
|
-
const submissionController =
|
|
110
|
-
new StagedCellSubmissionController(),
|
|
111
|
-
)
|
|
109
|
+
const [submissionController] = useState(
|
|
110
|
+
() => new StagedCellSubmissionController(),
|
|
111
|
+
);
|
|
112
112
|
|
|
113
113
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
114
114
|
const { files, addFiles, removeFile } = useFileState();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { DatabaseIcon, DiamondPlusIcon, PlusIcon } from "lucide-react";
|
|
3
|
-
import { useState } from "react";
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
4
|
import { Button } from "@/components/editor/inputs/Inputs";
|
|
5
5
|
import { MinimalHotkeys } from "@/components/shortcuts/renderShortcut";
|
|
6
6
|
import {
|
|
@@ -36,7 +36,8 @@ export const CreateCellButton = ({
|
|
|
36
36
|
const { createNewCell, addSetupCellIfDoesntExist } = useCellActions();
|
|
37
37
|
const shortcut = `${oneClickShortcut}-Click`;
|
|
38
38
|
const [open, setOpen] = useState(false);
|
|
39
|
-
|
|
39
|
+
// Time the dropdown last opened, to ignore the click that opened it
|
|
40
|
+
const openedAt = useRef(0);
|
|
40
41
|
|
|
41
42
|
const baseTooltipContent =
|
|
42
43
|
getConnectionTooltip(connectionState) || tooltipContent;
|
|
@@ -83,9 +84,7 @@ export const CreateCellButton = ({
|
|
|
83
84
|
|
|
84
85
|
const openDropdown = () => {
|
|
85
86
|
setOpen(true);
|
|
86
|
-
|
|
87
|
-
// Allow interactions after a brief delay to prevent the dropdown items immediately being clicked
|
|
88
|
-
setTimeout(() => setJustOpened(false), 200);
|
|
87
|
+
openedAt.current = Date.now();
|
|
89
88
|
};
|
|
90
89
|
|
|
91
90
|
// We use onPointerDownCapture (not onPointerDown) to intercept events in
|
|
@@ -121,15 +120,14 @@ export const CreateCellButton = ({
|
|
|
121
120
|
const handleOpenChange = (isOpen: boolean) => {
|
|
122
121
|
setOpen(isOpen);
|
|
123
122
|
if (isOpen) {
|
|
124
|
-
|
|
125
|
-
// Allow interactions after a brief delay
|
|
126
|
-
setTimeout(() => setJustOpened(false), 200);
|
|
123
|
+
openedAt.current = Date.now();
|
|
127
124
|
}
|
|
128
125
|
};
|
|
129
126
|
|
|
130
127
|
const handleFirstItemClick = (e: React.MouseEvent) => {
|
|
131
|
-
// Hack to prevent the first item from being clicked when the dropdown is
|
|
132
|
-
|
|
128
|
+
// Hack to prevent the first item from being clicked when the dropdown is
|
|
129
|
+
// opened: allow interactions only after a brief delay
|
|
130
|
+
if (Date.now() - openedAt.current < 200) {
|
|
133
131
|
e.preventDefault();
|
|
134
132
|
e.stopPropagation();
|
|
135
133
|
return;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { EditorState } from "@codemirror/state";
|
|
4
|
+
import { EditorView } from "@codemirror/view";
|
|
5
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
6
|
+
import { createRef } from "react";
|
|
7
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
8
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
9
|
+
import { switchLanguage } from "@/core/codemirror/language/extension";
|
|
10
|
+
import { LanguageToggle } from "../language-toggle";
|
|
11
|
+
|
|
12
|
+
vi.mock("@/core/codemirror/language/extension", () => ({
|
|
13
|
+
switchLanguage: vi.fn(),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
describe("LanguageToggle", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
vi.mocked(switchLanguage).mockClear();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("uses the editor mounted after the button rendered", () => {
|
|
22
|
+
const editorViewRef = createRef<EditorView>();
|
|
23
|
+
const onAfterToggle = vi.fn();
|
|
24
|
+
render(
|
|
25
|
+
<TooltipProvider>
|
|
26
|
+
<LanguageToggle
|
|
27
|
+
editorViewRef={editorViewRef}
|
|
28
|
+
currentLanguageAdapter="python"
|
|
29
|
+
canSwitchToLanguage={true}
|
|
30
|
+
toType="markdown"
|
|
31
|
+
displayName="Markdown"
|
|
32
|
+
icon="Markdown"
|
|
33
|
+
onAfterToggle={onAfterToggle}
|
|
34
|
+
/>
|
|
35
|
+
</TooltipProvider>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
fireEvent.click(screen.getByRole("button", { name: "Markdown" }));
|
|
39
|
+
expect(switchLanguage).not.toHaveBeenCalled();
|
|
40
|
+
expect(onAfterToggle).not.toHaveBeenCalled();
|
|
41
|
+
|
|
42
|
+
const view = new EditorView({ state: EditorState.create() });
|
|
43
|
+
editorViewRef.current = view;
|
|
44
|
+
try {
|
|
45
|
+
fireEvent.click(screen.getByRole("button", { name: "Markdown" }));
|
|
46
|
+
expect(switchLanguage).toHaveBeenCalledWith(view, {
|
|
47
|
+
language: "markdown",
|
|
48
|
+
});
|
|
49
|
+
expect(onAfterToggle).toHaveBeenCalledOnce();
|
|
50
|
+
} finally {
|
|
51
|
+
view.destroy();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -572,7 +572,7 @@ const CellEditorInternal = ({
|
|
|
572
572
|
<div className="absolute top-1 right-5">
|
|
573
573
|
<LanguageToggles
|
|
574
574
|
code={code}
|
|
575
|
-
|
|
575
|
+
editorViewRef={editorViewRef}
|
|
576
576
|
currentLanguageAdapter={languageAdapter}
|
|
577
577
|
onAfterToggle={afterToggleMarkdown}
|
|
578
578
|
/>
|
|
@@ -13,7 +13,7 @@ import { Functions } from "@/utils/functions";
|
|
|
13
13
|
import { MarkdownIcon, PythonIcon } from "./icons";
|
|
14
14
|
|
|
15
15
|
interface LanguageTogglesProps {
|
|
16
|
-
|
|
16
|
+
editorViewRef: React.RefObject<EditorView | null>;
|
|
17
17
|
code: string;
|
|
18
18
|
currentLanguageAdapter: LanguageAdapter["type"] | undefined;
|
|
19
19
|
onAfterToggle: () => void;
|
|
@@ -25,7 +25,7 @@ interface LanguageTogglesProps {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
28
|
-
|
|
28
|
+
editorViewRef,
|
|
29
29
|
code,
|
|
30
30
|
currentLanguageAdapter,
|
|
31
31
|
onAfterToggle,
|
|
@@ -43,7 +43,7 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
43
43
|
return (
|
|
44
44
|
<div className={className}>
|
|
45
45
|
<LanguageToggle
|
|
46
|
-
|
|
46
|
+
editorViewRef={editorViewRef}
|
|
47
47
|
currentLanguageAdapter={currentLanguageAdapter}
|
|
48
48
|
canSwitchToLanguage={canUseSQL && currentLanguageAdapter === "python"}
|
|
49
49
|
icon={
|
|
@@ -58,7 +58,7 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
58
58
|
onAfterToggle={onAfterToggle}
|
|
59
59
|
/>
|
|
60
60
|
<LanguageToggle
|
|
61
|
-
|
|
61
|
+
editorViewRef={editorViewRef}
|
|
62
62
|
currentLanguageAdapter={currentLanguageAdapter}
|
|
63
63
|
canSwitchToLanguage={
|
|
64
64
|
canUseMarkdown && currentLanguageAdapter === "python"
|
|
@@ -75,7 +75,7 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
75
75
|
onAfterToggle={onAfterToggle}
|
|
76
76
|
/>
|
|
77
77
|
<LanguageToggle
|
|
78
|
-
|
|
78
|
+
editorViewRef={editorViewRef}
|
|
79
79
|
currentLanguageAdapter={currentLanguageAdapter}
|
|
80
80
|
canSwitchToLanguage={true}
|
|
81
81
|
icon={
|
|
@@ -95,7 +95,7 @@ export const LanguageToggles: React.FC<LanguageTogglesProps> = ({
|
|
|
95
95
|
|
|
96
96
|
interface Props {
|
|
97
97
|
className?: string;
|
|
98
|
-
|
|
98
|
+
editorViewRef: React.RefObject<EditorView | null>;
|
|
99
99
|
canSwitchToLanguage: boolean;
|
|
100
100
|
currentLanguageAdapter: LanguageAdapter["type"] | undefined;
|
|
101
101
|
toType: LanguageAdapter["type"];
|
|
@@ -105,7 +105,7 @@ interface Props {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
export const LanguageToggle: React.FC<Props> = ({
|
|
108
|
-
|
|
108
|
+
editorViewRef,
|
|
109
109
|
currentLanguageAdapter,
|
|
110
110
|
canSwitchToLanguage,
|
|
111
111
|
icon,
|
|
@@ -114,6 +114,7 @@ export const LanguageToggle: React.FC<Props> = ({
|
|
|
114
114
|
onAfterToggle,
|
|
115
115
|
}) => {
|
|
116
116
|
const handleClick = () => {
|
|
117
|
+
const editorView = editorViewRef.current;
|
|
117
118
|
if (!editorView) {
|
|
118
119
|
return;
|
|
119
120
|
}
|