@marimo-team/frontend 0.25.2-dev12 → 0.25.2-dev4
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/assets/{ConnectedDataExplorerComponent-BFDHLGyp.js → ConnectedDataExplorerComponent-DJ5jwKfp.js} +1 -1
- package/dist/assets/{ErrorBoundary-CtGZ1MAN.js → ErrorBoundary-BeE1cdgM.js} +2 -2
- package/dist/assets/{LazyAnyLanguageCodeMirror-CaEYnB8x.js → LazyAnyLanguageCodeMirror-B_IYTCX5.js} +2 -2
- package/dist/assets/{RunButton-YN1KKz4a.js → RunButton-C2kFUhyO.js} +1 -1
- package/dist/assets/{abnfDiagram-VCTEODGH-CqPJWAgx.js → abnfDiagram-VCTEODGH-CSPJSGaM.js} +1 -1
- package/dist/assets/{add-cell-with-ai-Dceg80EG.js → add-cell-with-ai-BFgdVPaN.js} +1 -1
- package/dist/assets/{agent-panel-CEG8eS3F.js → agent-panel-Dh7yWh9P.js} +1 -1
- package/dist/assets/{ai-model-dropdown-SOxGsjRY.js → ai-model-dropdown-DJ2elMLM.js} +1 -1
- package/dist/assets/{alert-dialog-BsB0FYEL.js → alert-dialog-CeE3i3Qa.js} +1 -1
- package/dist/assets/{any-language-editor-b9spizfh.js → any-language-editor-Cj_HzlZY.js} +1 -1
- package/dist/assets/{app-config-button-CTTg_TIX.js → app-config-button-DBCTefOX.js} +1 -1
- package/dist/assets/{architectureDiagram-5GKGNRK7-DXjBUUE6.js → architectureDiagram-5GKGNRK7-7iukRoC9.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-DS6I1u-N.js → blockDiagram-I7D4REHJ-cuhpQB60.js} +1 -1
- package/dist/assets/{button-qFeU84ax.js → button-BoklZTGL.js} +1 -1
- package/dist/assets/{cache-panel-Ct9EFgP7.js → cache-panel-C0oB1kE2.js} +1 -1
- package/dist/assets/{capabilities-BqUNf14U.js → capabilities-Bj3s1hGN.js} +1 -1
- package/dist/assets/{cells-CU9huD49.js → cells-CzugpTQu.js} +1 -1
- package/dist/assets/{chat-display-DWPnai8M.js → chat-display-DevO4F8W.js} +1 -1
- package/dist/assets/{chat-panel-DGnu6v96.js → chat-panel-BGw0bqDk.js} +1 -1
- package/dist/assets/{chat-ui-BqLN7iW4.js → chat-ui-CZZFGlZi.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-s8kQsL8K.js → chunk-IMKFNOWR-BIILwBhp.js} +1 -1
- package/dist/assets/{chunk-SHT3W25Y-CM7-8w1-.js → chunk-SHT3W25Y-BtLGdeDB.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-BErtDMhh.js → chunk-SVP7TREG-B0UfxhUP.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-CGVR3aYq.js → chunk-TICWLB2K-BP7vel_P.js} +1 -1
- package/dist/assets/{circle-CzTMKZwz.js → circle-CeQt3rdW.js} +1 -1
- package/dist/assets/{classDiagram-ZZMXUADV-isldMhyu.js → classDiagram-ZZMXUADV-CoNXKNMZ.js} +1 -1
- package/dist/assets/{classDiagram-v2-VYDZK3BY-isldMhyu.js → classDiagram-v2-VYDZK3BY-CoNXKNMZ.js} +1 -1
- package/dist/assets/{code-visibility-BGq9NyQN.js → code-visibility-BFNYI7hr.js} +1 -1
- package/dist/assets/{command-palette-CyBHUvlK.js → command-palette-DN4JoOLD.js} +1 -1
- package/dist/assets/{common-CdJQaC_v.js → common-DUCPhoyP.js} +1 -1
- package/dist/assets/{components-DsJLlugL.js → components-CK7CeYlo.js} +1 -1
- package/dist/assets/{components-zfCkpDjF.js → components-DAmFBASm.js} +1 -1
- package/dist/assets/{config-2Nts63h2.js → config-B4VJJibu.js} +1 -1
- package/dist/assets/{config-BdH5RvM0.js → config-BxZgoFvi.js} +1 -1
- package/dist/assets/{config-D7CP5wR5.js → config-DpGPGznL.js} +1 -1
- package/dist/assets/{copy-B--GzTEX.js → copy-BhJktFeI.js} +1 -1
- package/dist/assets/{copy-icon-DQuttmjH.js → copy-icon-DFhUGBjO.js} +1 -1
- package/dist/assets/{createReducer-CI8rlZE9.js → createReducer-BPvK7C_R.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-B7iZDq2a.js → cynefinDiagram-5FMLGOSQ-BARZRQBb.js} +1 -1
- package/dist/assets/{dagre-DkKsNZNe.js → dagre-DVyyr7Cb.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-CLT8-BB_.js → dagre-GXQ25YYZ-79s0lOP0.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-Bt4aaHfB.js → data-grid-overlay-editor-DPfnIudL.js} +1 -1
- package/dist/assets/{dependency-graph-panel-DPFdz5rd.js → dependency-graph-panel-BN4CLayU.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-SuzEYncV.js → diagram-S7CK7UJ4-BCviGhvd.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-cuBTTzq8.js → diagram-UQ7AKVKN-Ds-BT46T.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-h6SkZKIl.js → diagram-VX7I27RA-BtL2eh0t.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-C-Vebae0.js → diagram-Z3DM3KII-C6SmbLBS.js} +1 -1
- package/dist/assets/{dist-DFI04FfI.js → dist-CyYN7zJg.js} +1 -1
- package/dist/assets/{documentation-panel-YTTKKIe_.js → documentation-panel-CzRbXV5u.js} +1 -1
- package/dist/assets/{dropdown-menu-Crx6knLg.js → dropdown-menu-VuyoeQOD.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-Bm_qbW1t.js → ebnfDiagram-PWID7BFC-D_JU4cMQ.js} +1 -1
- package/dist/assets/{edit-page-CWbb1Sdk.js → edit-page-jGNYBqQo.js} +45 -45
- package/dist/assets/{erDiagram-RLTQ6QDP-Dwwt91bq.js → erDiagram-RLTQ6QDP-Z9MJ6X-r.js} +1 -1
- package/dist/assets/{error-entries-DvgFKvod.js → error-entries-CDSsy76p.js} +1 -1
- package/dist/assets/{error-panel-D1XBOiHc.js → error-panel-ABvjFG3p.js} +1 -1
- package/dist/assets/{feedback-button-CXjDdARJ.js → feedback-button-CZhLiwkO.js} +1 -1
- package/dist/assets/{file-explorer-panel-BKJMBA3O.js → file-explorer-panel-DTiEpmVE.js} +1 -1
- package/dist/assets/{file-name-input-Bd3Q-WUK.js → file-name-input-C1C8xrjA.js} +1 -1
- package/dist/assets/{filename-rhW-R6K2.js → filename-fxG7K_MU.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-CqLwY5NX.js → flowDiagram-HODETNUW-ncLciK2K.js} +1 -1
- package/dist/assets/{fullscreen-3wS6IaIC.js → fullscreen-BmzAqMKq.js} +1 -1
- package/dist/assets/{gallery-page-CrkxyZTA.js → gallery-page-Moi4ZdJ0.js} +1 -1
- package/dist/assets/{glide-data-editor-B5WqL5gm.js → glide-data-editor-CbsCWu-K.js} +4 -4
- package/dist/assets/{graphlib-6Yb0YQgW.js → graphlib-3maKwbRO.js} +1 -1
- package/dist/assets/has-cJsIKK9t.js +1 -0
- package/dist/assets/{home-page-BNKKAvoF.js → home-page-UAgVOkCZ.js} +1 -1
- package/dist/assets/{index-C9FPQNuH.js → index-DafnX1Xx.js} +8 -8
- package/dist/assets/{infoDiagram-27XIBGKW-dRXMROiS.js → infoDiagram-27XIBGKW-Dk8U81nJ.js} +1 -1
- package/dist/assets/{input-D4bMj5Nb.js → input-BDakodZ2.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-CvBCDJJe.js → ishikawaDiagram-5VMMS53U-CzHQlMUQ.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-fIKpyolW.js → kanban-definition-UXKFOSKX-CVyVYiI6.js} +1 -1
- package/dist/assets/{logs-panel-adAvx6o3.js → logs-panel-Bz5ysVX4.js} +1 -1
- package/dist/assets/{menu-items-D-vbZmqL.js → menu-items-BBdeXCvU.js} +1 -1
- package/dist/assets/{mermaid-DpSqZGNM.js → mermaid-D_jPUVqz.js} +4 -4
- package/dist/assets/{mindmap-definition-YA3MSWOX-B95LGKLt.js → mindmap-definition-YA3MSWOX-D5t6Aq5Z.js} +1 -1
- package/dist/assets/{number-overlay-editor-Bs5xzKX-.js → number-overlay-editor-FAD8sjFU.js} +1 -1
- package/dist/assets/{numbers-DyJNv6Vk.js → numbers-DsgsDslU.js} +1 -1
- package/dist/assets/{outline-panel-B9u6Wgol.js → outline-panel-85oiQ0XX.js} +1 -1
- package/dist/assets/{packages-panel-D-g71io7.js → packages-panel-ClKIaP5S.js} +1 -1
- package/dist/assets/{panels-C5xQNcZv.js → panels-B48zp96D.js} +3 -3
- package/dist/assets/{pegDiagram-XKGWAZYB-CMaSc5Ln.js → pegDiagram-XKGWAZYB-BTkTm4ej.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-CZY0tLgh.js → pieDiagram-E7YTZNPT-Bq6X88M1.js} +1 -1
- package/dist/assets/{process-output-CpF79y4D.js → process-output-Cg2ta3vY.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-BSMijs6s.js → railroadDiagram-O6MQD6OU-fv8HXW_g.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-DjzkUUZk.js → requirementDiagram-BXWQKSXE-DDOOMUfC.js} +1 -1
- package/dist/assets/{reveal-component-ZyDayfDQ.js → reveal-component-CR43gpTZ.js} +1 -1
- package/dist/assets/{run-page-Ba_64fL5.js → run-page-NR_KFWk8.js} +1 -1
- package/dist/assets/{scratchpad-panel-7bxRkpPb.js → scratchpad-panel-DHc-oVb1.js} +1 -1
- package/dist/assets/{scroll-to-bottom-button-BLNi0TGS.js → scroll-to-bottom-button-BSCkDXet.js} +1 -1
- package/dist/assets/{secrets-panel-DmKgIV5x.js → secrets-panel-C-65ZjnM.js} +1 -1
- package/dist/assets/{select-CWHHoM53.js → select-BplWpfFo.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-Dp7JdkJ6.js → sequenceDiagram-WJ2MYXX4-DdpBhQaS.js} +1 -1
- package/dist/assets/{session-ztCnZJHI.js → session-DXKMv4Bs.js} +1 -1
- package/dist/assets/{session-panel-D9qVJogC.js → session-panel-DiwQqIbt.js} +1 -1
- package/dist/assets/{snippets-panel-QdZvjlBm.js → snippets-panel-BLmXrneD.js} +1 -1
- package/dist/assets/{state-0NZOvqJz.js → state-Ozzur_f2.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-CR5QDK_-.js → stateDiagram-D77RDMKH-D3p19fac.js} +1 -1
- package/dist/assets/{stateDiagram-v2-MP3YSRHH-BmMYN-vz.js → stateDiagram-v2-MP3YSRHH-CplsDaDl.js} +1 -1
- package/dist/assets/{strings-LjhpYwmx.js → strings-BHZPE0Mc.js} +1 -1
- package/dist/assets/{swimlanes-42K2YHIH-By_1jYHM.js → swimlanes-42K2YHIH-CLxCSvU4.js} +1 -1
- package/dist/assets/{swimlanesDiagram-VR7AAH4N-DjMyvNFc.js → swimlanesDiagram-VR7AAH4N-DPoIFx8T.js} +1 -1
- package/dist/assets/{swiper-component-Cbtej5b-.js → swiper-component-rqJChT_P.js} +1 -1
- package/dist/assets/{terminal-Ri8br8XX.js → terminal-CY4h1UmO.js} +1 -1
- package/dist/assets/{timeline-definition-24CTP7MA-BjNxu6yh.js → timeline-definition-24CTP7MA-Cw2PY--x.js} +1 -1
- package/dist/assets/{toast-DXkezxWI.js → toast-KNfsFUiB.js} +1 -1
- package/dist/assets/{tooltip-CamoSiGF.js → tooltip-DR2Z2N4w.js} +1 -1
- package/dist/assets/{tooltip-BQ9qHrrN.js → tooltip-PLkI_UfK.js} +1 -1
- package/dist/assets/{tracing-BxMH9HGb.js → tracing-Q8NAdlrA.js} +1 -1
- package/dist/assets/{tracing-panel-EeL3md5x.js → tracing-panel-Ci4kY4dr.js} +2 -2
- package/dist/assets/{use-restore-focus-D0UtBPD6.js → use-restore-focus-B98SEiGc.js} +1 -1
- package/dist/assets/{useCellActionButton-Di4NkDbT.js → useCellActionButton-DpYtVfFe.js} +1 -1
- package/dist/assets/{useEventListener-CUPWI_1X.js → useEventListener-BdZUApHd.js} +1 -1
- package/dist/assets/{useInterval-DluQa5sq.js → useInterval-ChchS0Rl.js} +1 -1
- package/dist/assets/{useTheme-CnWB5G1X.js → useTheme-DcnXlv0_.js} +1 -1
- package/dist/assets/{vega-component-DGTXJwmx.js → vega-component-BpoSew4K.js} +1 -1
- package/dist/assets/{vega-embed-container-Din5FYpB.js → vega-embed-container-BOJG8mCA.js} +1 -1
- package/dist/assets/{vennDiagram-4TSXK5OY-BR66J2hx.js → vennDiagram-4TSXK5OY-D8bN6lVl.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-Kg0-lASD.js → wardleyDiagram-VM6X3IG4-CbZdo0SA.js} +1 -1
- package/dist/assets/{write-secret-modal-wFgr-1dA.js → write-secret-modal-BiG2tahJ.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-BSXFWSRW.js → xychartDiagram-S5SC5T6Z-DUUQ9tau.js} +1 -1
- package/dist/assets/{youtube-Ck_NlGi9.js → youtube-A9VT7NHb.js} +1 -1
- package/dist/index.html +31 -31
- package/package.json +1 -1
- package/src/components/editor/actions/useNotebookActions.tsx +0 -20
- package/src/core/edit-app.tsx +0 -16
- package/src/core/hotkeys/hotkeys.ts +0 -12
- package/src/plugins/impl/FileBrowserPlugin.tsx +15 -45
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +2 -85
- package/dist/assets/has-B4C7ywdy.js +0 -1
- package/src/components/editor/actions/__tests__/useSetOutputsExpanded.test.ts +0 -42
- package/src/components/editor/actions/useSetOutputsExpanded.ts +0 -67
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { type LucideIcon,
|
|
3
|
+
import { type LucideIcon, CornerLeftUp } from "lucide-react";
|
|
4
4
|
import { type JSX, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import {
|
|
@@ -12,6 +12,7 @@ import { Spinner } from "@/components/icons/spinner";
|
|
|
12
12
|
import { Button } from "@/components/ui/button";
|
|
13
13
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
14
14
|
import { Label } from "@/components/ui/label";
|
|
15
|
+
import { NativeSelect } from "@/components/ui/native-select";
|
|
15
16
|
import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
|
|
16
17
|
import { toast } from "@/components/ui/use-toast";
|
|
17
18
|
import { RANDOM_ID_ATTR } from "@/core/dom/ui-element-constants";
|
|
@@ -471,19 +472,12 @@ export const FileBrowser = ({
|
|
|
471
472
|
//
|
|
472
473
|
// Assumes that path contains at least one delimiter, which is true
|
|
473
474
|
// only if this is an absolute path.
|
|
474
|
-
const {
|
|
475
|
+
const { parentDirectories } = getProtocolAndParentDirectories({
|
|
475
476
|
path,
|
|
476
477
|
delimiter,
|
|
477
478
|
initialPath,
|
|
478
479
|
restrictNavigation,
|
|
479
480
|
});
|
|
480
|
-
const breadcrumbs = parentDirectories.toReversed().map((dir) => ({
|
|
481
|
-
path: dir,
|
|
482
|
-
name:
|
|
483
|
-
dir === protocol
|
|
484
|
-
? protocol
|
|
485
|
-
: (dir.split(delimiter).findLast(Boolean) ?? dir),
|
|
486
|
-
}));
|
|
487
481
|
|
|
488
482
|
const selectionKindLabel =
|
|
489
483
|
selectionMode === "all"
|
|
@@ -521,42 +515,18 @@ export const FileBrowser = ({
|
|
|
521
515
|
<div>
|
|
522
516
|
{error && <Banner kind="danger">{error.message}</Banner>}
|
|
523
517
|
{renderHeader()}
|
|
524
|
-
<
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
)}
|
|
537
|
-
<button
|
|
538
|
-
type="button"
|
|
539
|
-
title={crumb.path}
|
|
540
|
-
aria-current={isCurrent ? "page" : undefined}
|
|
541
|
-
onClick={() => {
|
|
542
|
-
if (!isCurrent) {
|
|
543
|
-
setNewPath(crumb.path);
|
|
544
|
-
}
|
|
545
|
-
}}
|
|
546
|
-
className={cn(
|
|
547
|
-
"rounded px-1 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring",
|
|
548
|
-
isCurrent
|
|
549
|
-
? "font-medium cursor-default"
|
|
550
|
-
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
551
|
-
)}
|
|
552
|
-
>
|
|
553
|
-
{crumb.name}
|
|
554
|
-
</button>
|
|
555
|
-
</li>
|
|
556
|
-
);
|
|
557
|
-
})}
|
|
558
|
-
</ol>
|
|
559
|
-
</nav>
|
|
518
|
+
<NativeSelect
|
|
519
|
+
className="mt-2 w-full"
|
|
520
|
+
placeholder={path}
|
|
521
|
+
value={path}
|
|
522
|
+
onChange={(e) => setNewPath(e.target.value)}
|
|
523
|
+
>
|
|
524
|
+
{parentDirectories.map((dir) => (
|
|
525
|
+
<option value={dir} key={dir}>
|
|
526
|
+
{dir}
|
|
527
|
+
</option>
|
|
528
|
+
))}
|
|
529
|
+
</NativeSelect>
|
|
560
530
|
|
|
561
531
|
{data && typeof data.total_count === "number" && (
|
|
562
532
|
<div className="text-xs text-muted-foreground mt-1 px-1">
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
fireEvent,
|
|
5
|
-
render,
|
|
6
|
-
screen,
|
|
7
|
-
waitFor,
|
|
8
|
-
within,
|
|
9
|
-
} from "@testing-library/react";
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
10
4
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
|
11
5
|
import { SetupMocks } from "@/__mocks__/common";
|
|
12
6
|
import { initialModeAtom } from "@/core/mode";
|
|
@@ -193,7 +187,7 @@ describe("FileBrowserPlugin keyboard accessibility", () => {
|
|
|
193
187
|
const docsRow = docs.closest('[role="row"]')!;
|
|
194
188
|
fireEvent.keyDown(docsRow, { key: "ArrowDown" }); // move active off the parent
|
|
195
189
|
fireEvent.click(docs); // navigate into "docs"
|
|
196
|
-
await
|
|
190
|
+
await screen.findByText("docs"); // listing reloads (mock returns same files)
|
|
197
191
|
const rows = screen.getAllByRole("row");
|
|
198
192
|
expect(rows[0]).toHaveAttribute("tabindex", "0");
|
|
199
193
|
// the focused row must match the only tabbable row
|
|
@@ -367,80 +361,3 @@ describe("FileBrowserPlugin keyboard accessibility", () => {
|
|
|
367
361
|
function rowFor(name: string): HTMLElement {
|
|
368
362
|
return screen.getByText(name).closest('[role="row"]') as HTMLElement;
|
|
369
363
|
}
|
|
370
|
-
|
|
371
|
-
describe("FileBrowserPlugin breadcrumbs", () => {
|
|
372
|
-
function breadcrumbs() {
|
|
373
|
-
return within(
|
|
374
|
-
screen.getByRole("navigation", { name: "Current directory" }),
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
it("renders a crumb per ancestor with the current directory last", async () => {
|
|
379
|
-
renderBrowser();
|
|
380
|
-
await screen.findByText("docs");
|
|
381
|
-
const items = breadcrumbs().getAllByRole("listitem");
|
|
382
|
-
expect(items.map((li) => li.textContent)).toEqual(["/", "home", "user"]);
|
|
383
|
-
expect(breadcrumbs().getByRole("button", { name: "user" })).toHaveAttribute(
|
|
384
|
-
"aria-current",
|
|
385
|
-
"page",
|
|
386
|
-
);
|
|
387
|
-
expect(
|
|
388
|
-
breadcrumbs().getByRole("button", { name: "home" }),
|
|
389
|
-
).not.toHaveAttribute("aria-current");
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
it("keeps focus on a crumb after navigating to it", async () => {
|
|
393
|
-
const { listDirectory } = renderBrowser();
|
|
394
|
-
await screen.findByText("docs");
|
|
395
|
-
const home = breadcrumbs().getByRole("button", { name: "home" });
|
|
396
|
-
home.focus();
|
|
397
|
-
fireEvent.click(home);
|
|
398
|
-
await waitFor(() =>
|
|
399
|
-
expect(listDirectory).toHaveBeenLastCalledWith({ path: "/home" }),
|
|
400
|
-
);
|
|
401
|
-
const current = breadcrumbs().getByRole("button", { name: "home" });
|
|
402
|
-
expect(current).toHaveAttribute("aria-current", "page");
|
|
403
|
-
expect(current).toBe(home);
|
|
404
|
-
expect(current).toHaveFocus();
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
it("does not reload when the current crumb is clicked", async () => {
|
|
408
|
-
const { listDirectory } = renderBrowser();
|
|
409
|
-
await screen.findByText("docs");
|
|
410
|
-
fireEvent.click(breadcrumbs().getByRole("button", { name: "user" }));
|
|
411
|
-
expect(listDirectory).toHaveBeenCalledTimes(1);
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
it("navigates to an ancestor when a crumb is clicked", async () => {
|
|
415
|
-
const { listDirectory } = renderBrowser();
|
|
416
|
-
await screen.findByText("docs");
|
|
417
|
-
fireEvent.click(breadcrumbs().getByRole("button", { name: "home" }));
|
|
418
|
-
await waitFor(() =>
|
|
419
|
-
expect(listDirectory).toHaveBeenLastCalledWith({ path: "/home" }),
|
|
420
|
-
);
|
|
421
|
-
fireEvent.click(breadcrumbs().getByRole("button", { name: "/" }));
|
|
422
|
-
await waitFor(() =>
|
|
423
|
-
expect(listDirectory).toHaveBeenLastCalledWith({ path: "/" }),
|
|
424
|
-
);
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
it("hides ancestors outside the initial path when navigation is restricted", async () => {
|
|
428
|
-
render(
|
|
429
|
-
<FileBrowser
|
|
430
|
-
initialPath="/home/user"
|
|
431
|
-
filetypes={[]}
|
|
432
|
-
selectionMode="all"
|
|
433
|
-
multiple={true}
|
|
434
|
-
label={null}
|
|
435
|
-
restrictNavigation={true}
|
|
436
|
-
value={[]}
|
|
437
|
-
setValue={vi.fn()}
|
|
438
|
-
host={document.createElement("div")}
|
|
439
|
-
list_directory={mockListDirectory(FILES)}
|
|
440
|
-
/>,
|
|
441
|
-
);
|
|
442
|
-
await screen.findByText("docs");
|
|
443
|
-
const items = breadcrumbs().getAllByRole("listitem");
|
|
444
|
-
expect(items.map((li) => li.textContent)).toEqual(["user"]);
|
|
445
|
-
});
|
|
446
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Wa as e}from"./index-C9FPQNuH.js";var t=Object.prototype.hasOwnProperty;function n(e,n){return e!=null&&t.call(e,n)}function r(t,r){return t!=null&&e(t,r,n)}export{r as t};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
import { MockNotebook } from "@/__mocks__/notebook";
|
|
5
|
-
import type { OutputMessage } from "@/core/kernel/messages";
|
|
6
|
-
import { outputExpansionConfigs } from "../useSetOutputsExpanded";
|
|
7
|
-
|
|
8
|
-
const output: OutputMessage = {
|
|
9
|
-
channel: "output",
|
|
10
|
-
mimetype: "text/plain",
|
|
11
|
-
data: "hello",
|
|
12
|
-
timestamp: 0,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
describe("outputExpansionConfigs", () => {
|
|
16
|
-
const [withOutput, withoutOutput, expanded, expandedWithoutOutput] =
|
|
17
|
-
MockNotebook.cellIds();
|
|
18
|
-
const notebook = MockNotebook.notebookState({
|
|
19
|
-
cellData: {
|
|
20
|
-
[withOutput]: {},
|
|
21
|
-
[withoutOutput]: {},
|
|
22
|
-
[expanded]: { config: { expand_output: true } },
|
|
23
|
-
[expandedWithoutOutput]: { config: { expand_output: true } },
|
|
24
|
-
},
|
|
25
|
-
cellRuntime: {
|
|
26
|
-
[withOutput]: { output },
|
|
27
|
-
[expanded]: { output },
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("expands clamped cells with output and skips cells without output", () => {
|
|
32
|
-
expect(outputExpansionConfigs(notebook, true)).toEqual({
|
|
33
|
-
[withOutput]: { expand_output: true },
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("clamps expanded cells with output and skips cells without output", () => {
|
|
38
|
-
expect(outputExpansionConfigs(notebook, false)).toEqual({
|
|
39
|
-
[expanded]: { expand_output: false },
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { useCallback } from "react";
|
|
4
|
-
import {
|
|
5
|
-
getNotebook,
|
|
6
|
-
type NotebookState,
|
|
7
|
-
useCellActions,
|
|
8
|
-
} from "@/core/cells/cells";
|
|
9
|
-
import type { CellId } from "@/core/cells/ids";
|
|
10
|
-
import { isOutputEmpty } from "@/core/cells/outputs";
|
|
11
|
-
import { useRequestClient } from "@/core/network/requests";
|
|
12
|
-
import type { CellConfig } from "@/core/network/types";
|
|
13
|
-
import { Objects } from "@/utils/objects";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* The `expand_output` config changes needed to expand or clamp every output.
|
|
17
|
-
*
|
|
18
|
-
* Both actions skip cells without output, so their source isn't annotated
|
|
19
|
-
* with a config that has no effect.
|
|
20
|
-
*/
|
|
21
|
-
export function outputExpansionConfigs(
|
|
22
|
-
notebook: NotebookState,
|
|
23
|
-
expanded: boolean,
|
|
24
|
-
): Record<CellId, Partial<CellConfig>> {
|
|
25
|
-
const configs: Record<CellId, Partial<CellConfig>> = {};
|
|
26
|
-
for (const cellId of notebook.cellIds.inOrderIds) {
|
|
27
|
-
const cell = notebook.cellData[cellId];
|
|
28
|
-
if (
|
|
29
|
-
cell === undefined ||
|
|
30
|
-
(cell.config.expand_output ?? false) === expanded
|
|
31
|
-
) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (isOutputEmpty(notebook.cellRuntime[cellId]?.output)) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
configs[cellId] = { expand_output: expanded };
|
|
38
|
-
}
|
|
39
|
-
return configs;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Hook returning a callback that shows every cell's output in full, or clamps
|
|
44
|
-
* every output to a fixed height, by setting each cell's `expand_output` config.
|
|
45
|
-
*/
|
|
46
|
-
export const useSetOutputsExpanded = () => {
|
|
47
|
-
const { updateCellConfig } = useCellActions();
|
|
48
|
-
const { saveCellConfig } = useRequestClient();
|
|
49
|
-
|
|
50
|
-
return useCallback(
|
|
51
|
-
async (expanded: boolean) => {
|
|
52
|
-
const newConfigs = outputExpansionConfigs(getNotebook(), expanded);
|
|
53
|
-
|
|
54
|
-
const entries = Objects.entries(newConfigs);
|
|
55
|
-
if (entries.length === 0) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
await saveCellConfig({ configs: newConfigs });
|
|
60
|
-
|
|
61
|
-
for (const [cellId, config] of entries) {
|
|
62
|
-
updateCellConfig({ cellId, config });
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
[updateCellConfig, saveCellConfig],
|
|
66
|
-
);
|
|
67
|
-
};
|