@marimo-team/islands 0.23.3-dev7 → 0.23.3-dev8
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/{chat-ui-CTt4WX0V.js → chat-ui-BLFhPclV.js} +2 -2
- package/dist/{html-to-image-BdsDysfl.js → html-to-image-XYwXqg2E.js} +2107 -2107
- package/dist/main.js +6 -6
- package/dist/{process-output-COL2Pf5I.js → process-output-BDVjDpbu.js} +1 -1
- package/dist/{reveal-component-Cd5Y35Ny.js → reveal-component-CrnLosc4.js} +2 -2
- package/dist/{slide-BEerfanN.js → slide-Dl7Rf496.js} +1 -1
- package/package.json +1 -1
- package/src/components/editor/file-tree/__tests__/requesting-tree.test.ts +84 -2
- package/src/components/editor/file-tree/file-explorer.tsx +142 -203
- package/src/components/editor/file-tree/file-name-input.tsx +41 -0
- package/src/components/editor/file-tree/file-operations.tsx +266 -0
- package/src/components/editor/file-tree/requesting-tree.tsx +68 -49
- package/src/components/home/state.ts +13 -1
- package/src/components/pages/home-page.tsx +116 -10
- package/src/core/network/requests-network.ts +0 -3
- package/src/utils/__tests__/path.test.ts +20 -0
- package/src/utils/pathUtils.test.ts +141 -1
- package/src/utils/pathUtils.ts +46 -0
- package/src/utils/paths.ts +9 -1
package/dist/main.js
CHANGED
|
@@ -22,18 +22,18 @@ import { _ as Logger, c as Objects, g as cn, h as Events, i as NOT_SET, l as use
|
|
|
22
22
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
23
23
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
24
24
|
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-TGGAUEWp.js";
|
|
25
|
-
import { An as FileText, B as safeExtractSetUIElementMessageBuffers, C as AccordionContent, Dn as LoaderCircle, E as BorderAllIcon, F as base64ToDataView, Fn as CircleAlert, Gt as requestClientAtom, H as hasRunAnyCellAtom, In as Braces, It as PluralWords, J as notebookOutline, K as getCellNames, Kt as useRequestClient, L as dataViewToBase64, Lt as DATA_TYPE_ICON, Mn as Database, Nn as Columns2, Nt as jotaiJsonStorage, On as Layers, Ot as DeferredRequestRegistry, Pn as CircleX, Q as useCellIds, Qt as NotebookScopedLocalStorage, Rt as getDataTypeColor, S as Accordion, Sn as Trigger2, St as MarkdownLanguageAdapter, T as AccordionTrigger, Tn as PaintRoller, Tt as Paths, Ut as convertStatsName, V as renderHTML, W as createActions, Wt as getRequestClient, X as reducer, Y as numColumnsAtom, Z as useCellActions, _t as getValidName, a as useLastFocusedCellId, an as HTMLCellId, at as initialModeAtom, bn as Item$1, bt as Checkbox, c as Popover$1, cn as findCellId, d as PopoverTrigger, dn as jsonParseWithSpecialChar, dt as isErrorMime, et as createCell, f as isOutputEmpty, ft as headingToIdentifier, gn as selectAtom, hn as atomWithStorage, i as useCellFocusActions, it as getInitialAppMode, jn as Eye, jt as repl, k as ChevronDownIcon, kn as Info, kt as generateUUID, ln as OBJECT_ID_ATTR, lt as outputIsLoading, mn as atomWithReducer, nn as parseDataset, o as maybeAddAltairImport, ot as kioskModeAtom, p as useExpandedConsoleOutput, q as notebookAtom, qt as isUninstantiated, r as LazyAnyLanguageCodeMirror, rn as parseInitialValue, s as Spinner, sn as UIElementId, tn as parseAttrValue, u as PopoverContent, un as RANDOM_ID_ATTR, ut as outputIsStale, vt as isInternalCellName, w as AccordionItem, wn as Table2, wt as PathBuilder, xn as Root2$2, xt as customPythonLanguageSupport, yn as Content2, yt as normalizeName, zt as require_client, __tla as __tla_0 } from "./html-to-image-
|
|
25
|
+
import { An as FileText, B as safeExtractSetUIElementMessageBuffers, C as AccordionContent, Dn as LoaderCircle, E as BorderAllIcon, F as base64ToDataView, Fn as CircleAlert, Gt as requestClientAtom, H as hasRunAnyCellAtom, In as Braces, It as PluralWords, J as notebookOutline, K as getCellNames, Kt as useRequestClient, L as dataViewToBase64, Lt as DATA_TYPE_ICON, Mn as Database, Nn as Columns2, Nt as jotaiJsonStorage, On as Layers, Ot as DeferredRequestRegistry, Pn as CircleX, Q as useCellIds, Qt as NotebookScopedLocalStorage, Rt as getDataTypeColor, S as Accordion, Sn as Trigger2, St as MarkdownLanguageAdapter, T as AccordionTrigger, Tn as PaintRoller, Tt as Paths, Ut as convertStatsName, V as renderHTML, W as createActions, Wt as getRequestClient, X as reducer, Y as numColumnsAtom, Z as useCellActions, _t as getValidName, a as useLastFocusedCellId, an as HTMLCellId, at as initialModeAtom, bn as Item$1, bt as Checkbox, c as Popover$1, cn as findCellId, d as PopoverTrigger, dn as jsonParseWithSpecialChar, dt as isErrorMime, et as createCell, f as isOutputEmpty, ft as headingToIdentifier, gn as selectAtom, hn as atomWithStorage, i as useCellFocusActions, it as getInitialAppMode, jn as Eye, jt as repl, k as ChevronDownIcon, kn as Info, kt as generateUUID, ln as OBJECT_ID_ATTR, lt as outputIsLoading, mn as atomWithReducer, nn as parseDataset, o as maybeAddAltairImport, ot as kioskModeAtom, p as useExpandedConsoleOutput, q as notebookAtom, qt as isUninstantiated, r as LazyAnyLanguageCodeMirror, rn as parseInitialValue, s as Spinner, sn as UIElementId, tn as parseAttrValue, u as PopoverContent, un as RANDOM_ID_ATTR, ut as outputIsStale, vt as isInternalCellName, w as AccordionItem, wn as Table2, wt as PathBuilder, xn as Root2$2, xt as customPythonLanguageSupport, yn as Content2, yt as normalizeName, zt as require_client, __tla as __tla_0 } from "./html-to-image-XYwXqg2E.js";
|
|
26
26
|
import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-CO1e63h_.js";
|
|
27
27
|
import { o as useSize, s as Root$3, u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
28
28
|
import { A as SquareFunction, C as DEFAULT_COLOR_SCHEME, D as SCALE_TYPE_DESCRIPTIONS, E as EMPTY_VALUE$1, O as TIME_UNIT_DESCRIPTIONS, S as DEFAULT_AGGREGATION, T as DEFAULT_TIME_UNIT, _ as AGGREGATION_TYPE_DESCRIPTIONS, a as AGGREGATION_FNS$1, b as COLOR_SCHEMES, c as COLOR_BY_FIELDS, d as NONE_VALUE, f as SELECTABLE_DATA_TYPES, g as TIME_UNITS, h as STRING_AGGREGATION_FNS, i as convertDataTypeToSelectable, j as ChartColumn, k as escapeFieldName, l as COMBINED_TIME_UNITS, m as SORT_TYPES, n as createSpecWithoutData, o as BIN_AGGREGATION, p as SINGLE_TIME_UNITS, r as isFieldSet, s as CHART_TYPES, t as augmentSpecWithData, u as ChartType, v as AGGREGATION_TYPE_ICON, w as DEFAULT_MAX_BINS_FACET, x as COUNT_FIELD, y as CHART_TYPE_ICON } from "./spec-BKWq0wn2.js";
|
|
29
|
-
import { $ as CommandItem, A as TableHeader, B as usePrevious$1, C as Toggle, Ct as Download, D as TableBody, Dt as ChevronsDownUp, E as Table, Et as ChevronsLeft, F as renderCellValue, G as SELECT_COLUMN_ID, H as loadTableAndRawData, I as ColumnChartContext, J as getMimeValues, K as TOO_MANY_ROWS, L as ColumnChartSpecModel, M as NAMELESS_COLUMN_PREFIX, N as generateColumns, O as TableCell, Ot as ChevronLeft, P as inferFieldTypes, Q as CommandInput, R as DelayMount, S as slotsController, St as Ellipsis, T as Provider$1, Tt as ChevronsRight, U as loadTableData, V as getPageIndexForRow, W as INDEX_COLUMN_NAME, X as Command, Y as filtersToFilterGroup, Z as CommandEmpty, _ as contextAwarePanelOpen, _t as isStaticNotebook, a as DataTable, at as TabsList, b as isCellAwareAtom, bt as Funnel, c as downloadBlob, ct as ChartInfoState, d as Filenames, dt as useOverflowDetection, et as CommandList, f as prettifyRowColumnCount, ft as RenderTextWithLinks, g as PANEL_TYPES, gt as getStaticVirtualFiles, h as ContextAwarePanelItem, ht as EmotionCacheProvider, i as OutputRenderer, it as TabsContent, j as TableRow, k as TableHead, kt as ArrowDownWideNarrow, l as downloadByURL, lt as ChartLoadingState, m as useInternalStateWithSync, mt as HtmlOutput, n as JsonOutput, nt as Maps, o as InstallPackageButton, ot as TabsTrigger, p as prettifyRowCount, pt as Kbd, q as toFieldTypes, r as OutputArea, rt as Tabs, s as ADD_PRINTING_CLASS, st as ChartErrorState, t as Slide, tt as CommandSeparator, u as downloadHTMLAsImage, ut as LazyVegaEmbed, v as contextAwarePanelOwner, vt as TextWrap, w as Fill, wt as ChevronsUpDown, x as SlotNames, y as contextAwarePanelType, yt as GripHorizontal, z as useIntersectionObserver, __tla as __tla_2 } from "./slide-
|
|
29
|
+
import { $ as CommandItem, A as TableHeader, B as usePrevious$1, C as Toggle, Ct as Download, D as TableBody, Dt as ChevronsDownUp, E as Table, Et as ChevronsLeft, F as renderCellValue, G as SELECT_COLUMN_ID, H as loadTableAndRawData, I as ColumnChartContext, J as getMimeValues, K as TOO_MANY_ROWS, L as ColumnChartSpecModel, M as NAMELESS_COLUMN_PREFIX, N as generateColumns, O as TableCell, Ot as ChevronLeft, P as inferFieldTypes, Q as CommandInput, R as DelayMount, S as slotsController, St as Ellipsis, T as Provider$1, Tt as ChevronsRight, U as loadTableData, V as getPageIndexForRow, W as INDEX_COLUMN_NAME, X as Command, Y as filtersToFilterGroup, Z as CommandEmpty, _ as contextAwarePanelOpen, _t as isStaticNotebook, a as DataTable, at as TabsList, b as isCellAwareAtom, bt as Funnel, c as downloadBlob, ct as ChartInfoState, d as Filenames, dt as useOverflowDetection, et as CommandList, f as prettifyRowColumnCount, ft as RenderTextWithLinks, g as PANEL_TYPES, gt as getStaticVirtualFiles, h as ContextAwarePanelItem, ht as EmotionCacheProvider, i as OutputRenderer, it as TabsContent, j as TableRow, k as TableHead, kt as ArrowDownWideNarrow, l as downloadByURL, lt as ChartLoadingState, m as useInternalStateWithSync, mt as HtmlOutput, n as JsonOutput, nt as Maps, o as InstallPackageButton, ot as TabsTrigger, p as prettifyRowCount, pt as Kbd, q as toFieldTypes, r as OutputArea, rt as Tabs, s as ADD_PRINTING_CLASS, st as ChartErrorState, t as Slide, tt as CommandSeparator, u as downloadHTMLAsImage, ut as LazyVegaEmbed, v as contextAwarePanelOwner, vt as TextWrap, w as Fill, wt as ChevronsUpDown, x as SlotNames, y as contextAwarePanelType, yt as GripHorizontal, z as useIntersectionObserver, __tla as __tla_2 } from "./slide-Dl7Rf496.js";
|
|
30
30
|
import { c as Calendar, i as createReducerAndAtoms, n as useOnUnmount, o as ToggleLeft, r as Badge, t as useOnMount } from "./useLifecycle-smVfjLNI.js";
|
|
31
31
|
import { n as $fb18d541ea1ad717$export$ad991b66133851cf, r as $5a387cc49350e6db$export$722debc0e56fea39, t as $896ba0a80a8f4d36$export$85fd5fdf27bacc79 } from "./useDateFormatter-B3mCQMP3.js";
|
|
32
32
|
import { t as Check } from "./check-CFM2mVDr.js";
|
|
33
33
|
import { A as Trigger$1, C as $a916eb452884faea$export$b7a616150fdb9f44, D as $b5e257d569688ac6$export$535bd6ca7f90a273, E as $18f2051aff69b9bf$export$a54013f0d02a8f82, F as X, L as ChevronDown, M as usePrevious$2, N as useDirection, P as createCollection, S as logNever, T as $18f2051aff69b9bf$export$43bb16f9c6d9e3f7, a as SelectGroup, c as SelectSeparator, d as NativeSelect, f as selectStyles, i as SelectContent, j as clamp$2, k as Icon, l as SelectTrigger, n as capitalize, o as SelectItem, r as Select, s as SelectLabel, t as Strings, u as SelectValue, w as $488c6ddbf4ef74c2$export$cc77c4ff7e8673c5, x as assertNever } from "./strings-B_FOH6eV.js";
|
|
34
34
|
import { $ as $e5be200c675c3b3a$export$aca958c65c314e6c, A as $d2b4bc8c273e7be6$export$24d547caef80ccd1, At as $c87311424ea30a05$export$fedb369cb70207f1, B as $64fa3d84918910a7$export$c62b8e45d58ddad9, Bt as $431fbd86ca7dc216$export$f21a1ffae260145a, C as $a049562f99e7db0e$export$eb2fcfdbd7ba97d4, Ct as $8ae05eaa5c114e9c$export$7f54fc3180508a52, D as $ee014567cb39d3f0$export$ff05c3ac10437e03, Dt as $c87311424ea30a05$export$78551043582a6a98, E as $ee014567cb39d3f0$export$f551688fc98f2e09, Et as $c87311424ea30a05$export$6446a186d09e379e, F as $64fa3d84918910a7$export$2881499e37b75b9a, Ft as $d4ee10de306f2510$export$b4f377a2b6254582, H as $64fa3d84918910a7$export$ef03459518577ad4, Ht as $bdb11010cef70236$export$b4cc09c592e8fdb8, I as $64fa3d84918910a7$export$29f1550f4b0d4415, It as $d4ee10de306f2510$export$cd4e5573fbe2b576, J as $d2e8511e6f209edf$export$e908e06f4b8e3402, K as useDebounceControlledState, L as $64fa3d84918910a7$export$4d86445c2cf5e3, Lt as $d4ee10de306f2510$export$e58f029f0fbfdb29, M as $01b77f81d0f07f68$export$75b6ee27786ba447, Mt as $65484d02dcb7eb3e$export$457c3d6518dd4c6f, N as $01b77f81d0f07f68$export$b04be29aa201d4f5, Nt as $3ef42575df84b30b$export$9d1611c77c2fe928, O as $514c0188e459b4c0$export$5f1af8db9871e1d6, Ot as $c87311424ea30a05$export$9ac100e40613ea10, P as $f39a9eba43920ace$export$b5d7cc18bb8d2b59, Pt as $d4ee10de306f2510$export$4282f70798064fe0, Q as $e5be200c675c3b3a$export$a763b9476acd3eb, R as $64fa3d84918910a7$export$9d4c57ee4c6ffdd8, Rt as $f4e2df6bd15f8569$export$98658e8c59125e6a, S as $3985021b0ad6602f$export$f5b8910cec6cf069, St as $e9faafb641e167db$export$90fc3a17d93f704c, T as $d3e0e05bdfcf66bd$export$c24727297075ec6a, Tt as $313b98861ee5dd6c$export$d6875122194c7b44, U as $64fa3d84918910a7$export$fabf2dc03a41866e, Ut as $bdb11010cef70236$export$f680877a34711e37, V as $64fa3d84918910a7$export$df3a06d6289f983e, Vt as $ff5963eb1fccf552$export$e08e3b67e392101e, Wt as $f0a04ccd8dbdd83b$export$e5c5a5f917a5871c, X as $e93e671b31057976$export$b8473d3665f3a75a, Y as $2baaea4c71418dea$export$294aa081a6c6f55d, Z as $e5be200c675c3b3a$export$75ee7c75d68f5b0e, _t as $9446cca9a3875146$export$7d15b64cf5a3a4c4, a as NumberField, at as $6c7bd7858deea686$export$cd11ab140839f11d, b as DropdownMenuTrigger, bt as $b4b717babfbb907b$export$bebd5a1431fec25d, c as prettyNumber, cn as Item$2, ct as $6db58dc88e78b024$export$2f817fcdc4b89ae0, d as DropdownMenuContent, dt as $9ab94262bd0047c7$export$420e68273165f4ec, et as $e5be200c675c3b3a$export$dad6ae84456c676a, f as DropdownMenuGroup, fn as Circle, ft as $3ad3f6e1647bc98d$export$80f3e147d781571c, g as DropdownMenuSeparator, gt as $ae1eeba8b9eafd08$export$5165eccb35aaadb5, ht as _class_private_field_init, i as OnBlurredInput, it as $701a24aa0da5b062$export$ea18c227d4417cc3, j as $d2b4bc8c273e7be6$export$353f5b6fc5456de1, jt as $7215afc6de606d6b$export$de79e2c695e052f3, k as $514c0188e459b4c0$export$9afb8bc826b033ea, kt as $c87311424ea30a05$export$a11b0059900ceec8, l as prettyScientificNumber, ln as Root$4, lt as $5b160d28a433310d$export$c17fa47878dc55b6, m as DropdownMenuLabel, mt as $f6c31cce2adf654f$export$45712eceda6fad21, n as DebouncedNumberInput, nt as $319e236875307eab$export$a9b970dcc4ae71a9, ot as $fca6afa0e843324b$export$87b761675e8eaa10, p as DropdownMenuItem, pn as ChevronRight, pt as $507fabe10e71c6fb$export$630ff653c5ada6a9, q as useDebouncedCallback, r as Input, rt as $f7dceffc5ad7768b$export$4e328f61c538687f, st as $fca6afa0e843324b$export$f12b703ca79dfbb1, t as DebouncedInput, tt as $e5be200c675c3b3a$export$fc1a364ae1f3ff10, u as DropdownMenu, un as createRovingFocusGroupScope, ut as $6179b936705e76d3$export$ae780daf29e6d456, vt as $458b0a5536c1a7cf$export$40bfa8c7b0832715, w as $a049562f99e7db0e$export$f9c6924e160136d1, wt as $df56164dff5785e2$export$4338b53315abf666, x as $3985021b0ad6602f$export$37fb8590cf2c088c, xt as $99facab73266f662$export$5add1d006293d136, yt as $b4b717babfbb907b$export$4c063cf1350e6fed, z as $64fa3d84918910a7$export$c245e6201fed2f75, zt as $431fbd86ca7dc216$export$b204af158042fbac } from "./input-Drx1pguW.js";
|
|
35
35
|
import { c as asRemoteURL, f as require_cuid2, g as CircleQuestionMark, h as isWasm, m as Deferred, u as appendQueryParams } from "./toDate-yqOcZ_tY.js";
|
|
36
|
-
import { a as MarimoIncomingMessageEvent, c as MarimoValueUpdateEvent, d as Trash2, f as File, i as PythonIcon, l as createInputEvent, n as blobToString, o as MarimoValueInputEvent, r as filesToBase64, s as MarimoValueReadyEvent, t as processOutput, u as deserializeBlob } from "./process-output-
|
|
36
|
+
import { a as MarimoIncomingMessageEvent, c as MarimoValueUpdateEvent, d as Trash2, f as File, i as PythonIcon, l as createInputEvent, n as blobToString, o as MarimoValueInputEvent, r as filesToBase64, s as MarimoValueReadyEvent, t as processOutput, u as deserializeBlob } from "./process-output-BDVjDpbu.js";
|
|
37
37
|
import { i as Pencil, n as Trash, r as Plus, t as BulkEdit } from "./types-DBtDeUKD.js";
|
|
38
38
|
import { t as require_react_dom } from "./react-dom-BWRJ_g_k.js";
|
|
39
39
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
@@ -13868,7 +13868,7 @@ Defaulting to \`null\`.`;
|
|
|
13868
13868
|
};
|
|
13869
13869
|
}
|
|
13870
13870
|
};
|
|
13871
|
-
var LazyChatbot = import_react.lazy(() => import("./chat-ui-
|
|
13871
|
+
var LazyChatbot = import_react.lazy(() => import("./chat-ui-BLFhPclV.js").then((e) => ({
|
|
13872
13872
|
default: e.Chatbot
|
|
13873
13873
|
}))), messageSchema = array(object({
|
|
13874
13874
|
id: string(),
|
|
@@ -44992,7 +44992,7 @@ ${c}
|
|
|
44992
44992
|
function asCellId(e) {
|
|
44993
44993
|
return typeof e == "string" ? e : null;
|
|
44994
44994
|
}
|
|
44995
|
-
var import_compiler_runtime$10 = require_compiler_runtime(), LazySlidesComponent = import_react.lazy(() => import("./reveal-component-
|
|
44995
|
+
var import_compiler_runtime$10 = require_compiler_runtime(), LazySlidesComponent = import_react.lazy(() => import("./reveal-component-CrnLosc4.js"));
|
|
44996
44996
|
const SlidesLayoutRenderer = (e) => {
|
|
44997
44997
|
var _a3;
|
|
44998
44998
|
let r = (0, import_compiler_runtime$10.c)(20), { cells: c, mode: l } = e, u = l === "read", d = useAtomValue(numColumnsAtom) > 1, [f, p] = (0, import_react.useState)(null), m = (0, import_react.useRef)(null), h, g;
|
|
@@ -45525,7 +45525,7 @@ ${c}
|
|
|
45525
45525
|
return Logger.warn("Failed to get version from mount config"), null;
|
|
45526
45526
|
}
|
|
45527
45527
|
}
|
|
45528
|
-
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.3-
|
|
45528
|
+
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.3-dev8"), showCodeInRunModeAtom = atom(true);
|
|
45529
45529
|
atom(null);
|
|
45530
45530
|
var VIRTUAL_FILE_REGEX = /\/@file\/([^\s"&'/]+)\.([\dA-Za-z]+)/g, VirtualFileTracker = class e {
|
|
45531
45531
|
constructor() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
2
2
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
3
|
-
import { nt as parseHtmlContent, tt as ansiToPlainText } from "./html-to-image-
|
|
3
|
+
import { nt as parseHtmlContent, tt as ansiToPlainText } from "./html-to-image-XYwXqg2E.js";
|
|
4
4
|
import { u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
5
5
|
import { t as Strings } from "./strings-B_FOH6eV.js";
|
|
6
6
|
import { t as require_jsx_runtime } from "./jsx-runtime-COBk7ree.js";
|
|
@@ -6,9 +6,9 @@ import { s as __toESM } from "./chunk-BNovOVIE.js";
|
|
|
6
6
|
import { _ as Logger, h as Events, t as Button } from "./button-CA5pI2YF.js";
|
|
7
7
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
8
8
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
9
|
-
import "./html-to-image-
|
|
9
|
+
import "./html-to-image-XYwXqg2E.js";
|
|
10
10
|
import "./chunk-5FQGJX7Z-CO1e63h_.js";
|
|
11
|
-
import { t as Slide, xt as Expand } from "./slide-
|
|
11
|
+
import { t as Slide, xt as Expand } from "./slide-Dl7Rf496.js";
|
|
12
12
|
import "./input-Drx1pguW.js";
|
|
13
13
|
import "./toDate-yqOcZ_tY.js";
|
|
14
14
|
import "./react-dom-BWRJ_g_k.js";
|
|
@@ -6,7 +6,7 @@ import { _ as Logger, c as Objects, g as cn, h as Events, p as composeRefs, r as
|
|
|
6
6
|
import { t as require_react } from "./react-DA-nE2FX.js";
|
|
7
7
|
import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
|
|
8
8
|
import { n as Copy, r as toast, t as copyToClipboard } from "./copy-TGGAUEWp.js";
|
|
9
|
-
import { $ as useCellNames, A as ChevronRightIcon, An as FileText, At as useChromeActions, C as AccordionContent, Cn as Wrench, Dn as LoaderCircle, Dt as goToCellLine, En as NotebookPen, Ft as PluralWord, G as getCellEditorView, I as base64ToUint8Array, In as Braces, Kt as useRequestClient, Ln as esm_default, Lt as DATA_TYPE_ICON, M as PinLeftIcon, Mt as adaptForLocalStorage, N as PinRightIcon, Nt as jotaiJsonStorage, O as CheckIcon, Q as useCellIds, R as extractBase64FromDataURL, Rn as import_lib, S as Accordion, T as AccordionTrigger, V as renderHTML, Wt as getRequestClient, Xt as extractAllTracebackInfo, Yt as elementContainsMarimoCellFile, Z as useCellActions, Zt as getTracebackInfo, an as HTMLCellId, bt as Checkbox, c as Popover, ct as viewStateAtom, d as PopoverTrigger, dn as jsonParseWithSpecialChar, en as filenameAtom, fn as jsonToMarkdown, g as getDatasourceContext, gt as displayCellName, hn as atomWithStorage, ht as getCellDomProps, in as CellOutputId, j as DotFilledIcon, l as PopoverClose$1, lt as outputIsLoading, m as useExpandedOutput, mt as DATA_CELL_ID, n as MarkdownRenderer, on as SCRATCH_CELL_ID, pn as jsonToTSV, pt as sanitizeHtml, q as notebookAtom, rt as AnsiUp, s as Spinner, st as useInstallAllowed, t as toPng, u as PopoverContent, vn as Close$1, w as AccordionItem, z as isDataURLString, __tla as __tla_0 } from "./html-to-image-
|
|
9
|
+
import { $ as useCellNames, A as ChevronRightIcon, An as FileText, At as useChromeActions, C as AccordionContent, Cn as Wrench, Dn as LoaderCircle, Dt as goToCellLine, En as NotebookPen, Ft as PluralWord, G as getCellEditorView, I as base64ToUint8Array, In as Braces, Kt as useRequestClient, Ln as esm_default, Lt as DATA_TYPE_ICON, M as PinLeftIcon, Mt as adaptForLocalStorage, N as PinRightIcon, Nt as jotaiJsonStorage, O as CheckIcon, Q as useCellIds, R as extractBase64FromDataURL, Rn as import_lib, S as Accordion, T as AccordionTrigger, V as renderHTML, Wt as getRequestClient, Xt as extractAllTracebackInfo, Yt as elementContainsMarimoCellFile, Z as useCellActions, Zt as getTracebackInfo, an as HTMLCellId, bt as Checkbox, c as Popover, ct as viewStateAtom, d as PopoverTrigger, dn as jsonParseWithSpecialChar, en as filenameAtom, fn as jsonToMarkdown, g as getDatasourceContext, gt as displayCellName, hn as atomWithStorage, ht as getCellDomProps, in as CellOutputId, j as DotFilledIcon, l as PopoverClose$1, lt as outputIsLoading, m as useExpandedOutput, mt as DATA_CELL_ID, n as MarkdownRenderer, on as SCRATCH_CELL_ID, pn as jsonToTSV, pt as sanitizeHtml, q as notebookAtom, rt as AnsiUp, s as Spinner, st as useInstallAllowed, t as toPng, u as PopoverContent, vn as Close$1, w as AccordionItem, z as isDataURLString, __tla as __tla_0 } from "./html-to-image-XYwXqg2E.js";
|
|
10
10
|
import { u as createLucideIcon } from "./dist-ESg7xyoD.js";
|
|
11
11
|
import { i as createReducerAndAtoms, r as Badge } from "./useLifecycle-smVfjLNI.js";
|
|
12
12
|
import { a as ListFilter, i as Table$1, o as ChartPie, t as $896ba0a80a8f4d36$export$85fd5fdf27bacc79 } from "./useDateFormatter-B3mCQMP3.js";
|
package/package.json
CHANGED
|
@@ -182,10 +182,24 @@ describe("RequestingTree", () => {
|
|
|
182
182
|
expect(mockOnChange).toHaveBeenCalled();
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
+
test("delete should drop a file on success", async () => {
|
|
186
|
+
sendDeleteFileOrFolder.mockResolvedValue({ success: true });
|
|
187
|
+
|
|
188
|
+
await requestingTree.delete("1.1");
|
|
189
|
+
expect(sendDeleteFileOrFolder).toHaveBeenCalledWith({
|
|
190
|
+
path: "/root/file1",
|
|
191
|
+
});
|
|
192
|
+
const lastCall = mockOnChange.mock.calls.at(-1);
|
|
193
|
+
expect(lastCall?.[0].map((f: { id: string }) => f.id)).toEqual([
|
|
194
|
+
"1.2",
|
|
195
|
+
"1.3",
|
|
196
|
+
]);
|
|
197
|
+
});
|
|
198
|
+
|
|
185
199
|
test("createFile should create a new file", async () => {
|
|
186
200
|
sendCreateFileOrFolder.mockResolvedValue({ success: true });
|
|
187
201
|
|
|
188
|
-
await requestingTree.createFile("file3", "1.2");
|
|
202
|
+
await requestingTree.createFile({ name: "file3", parentId: "1.2" });
|
|
189
203
|
expect(sendCreateFileOrFolder).toHaveBeenCalledWith({
|
|
190
204
|
path: "/root/folder1",
|
|
191
205
|
type: "file",
|
|
@@ -197,7 +211,11 @@ describe("RequestingTree", () => {
|
|
|
197
211
|
test("createFile should create a new notebook", async () => {
|
|
198
212
|
sendCreateFileOrFolder.mockResolvedValue({ success: true });
|
|
199
213
|
|
|
200
|
-
await requestingTree.createFile(
|
|
214
|
+
await requestingTree.createFile({
|
|
215
|
+
name: "notebook1",
|
|
216
|
+
parentId: "1.2",
|
|
217
|
+
type: "notebook",
|
|
218
|
+
});
|
|
201
219
|
expect(sendCreateFileOrFolder).toHaveBeenCalledWith({
|
|
202
220
|
path: "/root/folder1",
|
|
203
221
|
type: "notebook",
|
|
@@ -277,6 +295,70 @@ describe("RequestingTree", () => {
|
|
|
277
295
|
});
|
|
278
296
|
});
|
|
279
297
|
|
|
298
|
+
test("rename should NOT mutate the local tree on API failure", async () => {
|
|
299
|
+
sendRenameFileOrFolder.mockResolvedValue({
|
|
300
|
+
success: false,
|
|
301
|
+
message: "Error renaming",
|
|
302
|
+
});
|
|
303
|
+
const changesBefore = mockOnChange.mock.calls.length;
|
|
304
|
+
|
|
305
|
+
await requestingTree.rename("1.1", "file2");
|
|
306
|
+
|
|
307
|
+
// No further onChange calls should fire after the failed rename, so the
|
|
308
|
+
// tree stays in sync with the backend.
|
|
309
|
+
expect(mockOnChange.mock.calls.length).toBe(changesBefore);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test("delete should NOT drop the node on API failure", async () => {
|
|
313
|
+
sendDeleteFileOrFolder.mockResolvedValue({
|
|
314
|
+
success: false,
|
|
315
|
+
message: "Error deleting",
|
|
316
|
+
});
|
|
317
|
+
const changesBefore = mockOnChange.mock.calls.length;
|
|
318
|
+
|
|
319
|
+
await requestingTree.delete("1.1");
|
|
320
|
+
expect(sendDeleteFileOrFolder).toHaveBeenCalledWith({
|
|
321
|
+
path: "/root/file1",
|
|
322
|
+
});
|
|
323
|
+
expect(toast).toHaveBeenCalledWith({
|
|
324
|
+
title: "Failed",
|
|
325
|
+
description: "Error deleting",
|
|
326
|
+
});
|
|
327
|
+
expect(mockOnChange.mock.calls.length).toBe(changesBefore);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("move should NOT mutate the local tree when rename fails", async () => {
|
|
331
|
+
sendRenameFileOrFolder.mockResolvedValue({
|
|
332
|
+
success: false,
|
|
333
|
+
message: "Error moving",
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
await requestingTree.move(["1.1"], "1.2");
|
|
337
|
+
|
|
338
|
+
expect(toast).toHaveBeenCalledWith({
|
|
339
|
+
title: "Failed",
|
|
340
|
+
description: "Error moving",
|
|
341
|
+
});
|
|
342
|
+
// The last emitted state should still have file1 at the top level, not
|
|
343
|
+
// moved under folder1.
|
|
344
|
+
const lastCall = mockOnChange.mock.calls.at(-1);
|
|
345
|
+
expect(lastCall?.[0]).toEqual([
|
|
346
|
+
{ id: "1.1", name: "file1", path: "/root/file1" },
|
|
347
|
+
{
|
|
348
|
+
id: "1.2",
|
|
349
|
+
name: "folder1",
|
|
350
|
+
isDirectory: true,
|
|
351
|
+
path: "/root/folder1",
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
id: "1.3",
|
|
355
|
+
name: "folder2",
|
|
356
|
+
isDirectory: true,
|
|
357
|
+
path: "/root/folder2",
|
|
358
|
+
},
|
|
359
|
+
]);
|
|
360
|
+
});
|
|
361
|
+
|
|
280
362
|
test("copy should handle API failure", async () => {
|
|
281
363
|
sendCopyFileOrFolder.mockResolvedValue({
|
|
282
364
|
success: false,
|
|
@@ -6,21 +6,18 @@ import {
|
|
|
6
6
|
ArrowLeftIcon,
|
|
7
7
|
BetweenHorizontalStartIcon,
|
|
8
8
|
BracesIcon,
|
|
9
|
-
CopyIcon,
|
|
10
9
|
CopyMinusIcon,
|
|
11
10
|
DownloadIcon,
|
|
12
|
-
Edit3Icon,
|
|
13
11
|
ExternalLinkIcon,
|
|
14
12
|
EyeOffIcon,
|
|
15
13
|
FilePlus2Icon,
|
|
16
14
|
FolderPlusIcon,
|
|
17
15
|
ListTreeIcon,
|
|
18
16
|
PlaySquareIcon,
|
|
19
|
-
Trash2Icon,
|
|
20
17
|
UploadIcon,
|
|
21
18
|
ViewIcon,
|
|
22
19
|
} from "lucide-react";
|
|
23
|
-
import React, { Suspense, use,
|
|
20
|
+
import React, { Suspense, use, useRef, useState } from "react";
|
|
24
21
|
import {
|
|
25
22
|
type NodeApi,
|
|
26
23
|
type NodeRendererProps,
|
|
@@ -34,9 +31,15 @@ import {
|
|
|
34
31
|
type FileIconType,
|
|
35
32
|
guessFileIconType,
|
|
36
33
|
} from "@/components/editor/file-tree/file-icons";
|
|
34
|
+
import {
|
|
35
|
+
DeleteMenuItem,
|
|
36
|
+
DuplicateMenuItem,
|
|
37
|
+
FileActionsDropdown,
|
|
38
|
+
RenameMenuItem,
|
|
39
|
+
} from "@/components/editor/file-tree/file-operations";
|
|
40
|
+
import { FileNameInput } from "@/components/editor/file-tree/file-name-input";
|
|
37
41
|
import {
|
|
38
42
|
MENU_ITEM_ICON_CLASS,
|
|
39
|
-
MoreActionsButton,
|
|
40
43
|
RefreshIconButton,
|
|
41
44
|
TreeChevron,
|
|
42
45
|
} from "@/components/editor/file-tree/tree-actions";
|
|
@@ -46,11 +49,8 @@ import { useImperativeModal } from "@/components/modal/ImperativeModal";
|
|
|
46
49
|
import { AlertDialogDestructiveAction } from "@/components/ui/alert-dialog";
|
|
47
50
|
import { Button, buttonVariants } from "@/components/ui/button";
|
|
48
51
|
import {
|
|
49
|
-
DropdownMenu,
|
|
50
|
-
DropdownMenuContent,
|
|
51
52
|
DropdownMenuItem,
|
|
52
53
|
DropdownMenuSeparator,
|
|
53
|
-
DropdownMenuTrigger,
|
|
54
54
|
} from "@/components/ui/dropdown-menu";
|
|
55
55
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
56
56
|
import { toast } from "@/components/ui/use-toast";
|
|
@@ -69,7 +69,7 @@ import { downloadBlob } from "@/utils/download";
|
|
|
69
69
|
import { type Base64String, base64ToDataURL } from "@/utils/json/base64";
|
|
70
70
|
import { openNotebook } from "@/utils/links";
|
|
71
71
|
import type { FilePath } from "@/utils/paths";
|
|
72
|
-
import {
|
|
72
|
+
import { makeDuplicateName } from "@/utils/pathUtils";
|
|
73
73
|
import { jotaiJsonStorage } from "@/utils/storage/jotai";
|
|
74
74
|
import { useTreeDndManager } from "./dnd-wrapper";
|
|
75
75
|
import { FileViewer } from "./file-viewer";
|
|
@@ -131,7 +131,7 @@ export const FileExplorer: React.FC<{
|
|
|
131
131
|
openPrompt({
|
|
132
132
|
title: "File name",
|
|
133
133
|
onConfirm: async (name) => {
|
|
134
|
-
tree.createFile(name, null);
|
|
134
|
+
tree.createFile({ name, parentId: null });
|
|
135
135
|
},
|
|
136
136
|
});
|
|
137
137
|
});
|
|
@@ -140,7 +140,7 @@ export const FileExplorer: React.FC<{
|
|
|
140
140
|
openPrompt({
|
|
141
141
|
title: "Notebook name",
|
|
142
142
|
onConfirm: async (name) => {
|
|
143
|
-
tree.createFile(name, null, "notebook");
|
|
143
|
+
tree.createFile({ name, parentId: null, type: "notebook" });
|
|
144
144
|
},
|
|
145
145
|
});
|
|
146
146
|
});
|
|
@@ -392,33 +392,6 @@ const Show = ({
|
|
|
392
392
|
);
|
|
393
393
|
};
|
|
394
394
|
|
|
395
|
-
const Edit = ({ node }: { node: NodeApi<FileInfo> }) => {
|
|
396
|
-
const ref = useRef<HTMLInputElement>(null);
|
|
397
|
-
useEffect(() => {
|
|
398
|
-
ref.current?.focus();
|
|
399
|
-
// Select everything, but the extension
|
|
400
|
-
ref.current?.setSelectionRange(0, node.data.name.lastIndexOf("."));
|
|
401
|
-
}, [node.data.name]);
|
|
402
|
-
|
|
403
|
-
return (
|
|
404
|
-
<input
|
|
405
|
-
ref={ref}
|
|
406
|
-
className="flex-1 bg-transparent border border-border text-muted-foreground"
|
|
407
|
-
defaultValue={node.data.name}
|
|
408
|
-
onClick={(e) => e.stopPropagation()}
|
|
409
|
-
onBlur={() => node.reset()}
|
|
410
|
-
onKeyDown={(e) => {
|
|
411
|
-
if (e.key === "Escape") {
|
|
412
|
-
node.reset();
|
|
413
|
-
}
|
|
414
|
-
if (e.key === "Enter") {
|
|
415
|
-
node.submit(e.currentTarget.value);
|
|
416
|
-
}
|
|
417
|
-
}}
|
|
418
|
-
/>
|
|
419
|
-
);
|
|
420
|
-
};
|
|
421
|
-
|
|
422
395
|
const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
423
396
|
const { openFile, sendFileDetails } = useRequestClient();
|
|
424
397
|
const disableFileDownloads = useAtomValue(disableFileDownloadsAtom);
|
|
@@ -486,7 +459,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
486
459
|
openPrompt({
|
|
487
460
|
title: "File name",
|
|
488
461
|
onConfirm: async (name) => {
|
|
489
|
-
tree?.createFile(name, node.id);
|
|
462
|
+
tree?.createFile({ name, parentId: node.id });
|
|
490
463
|
},
|
|
491
464
|
});
|
|
492
465
|
});
|
|
@@ -496,7 +469,7 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
496
469
|
openPrompt({
|
|
497
470
|
title: "Notebook name",
|
|
498
471
|
onConfirm: async (name) => {
|
|
499
|
-
tree?.createFile(name, node.id, "notebook");
|
|
472
|
+
tree?.createFile({ name, parentId: node.id, type: "notebook" });
|
|
500
473
|
},
|
|
501
474
|
});
|
|
502
475
|
});
|
|
@@ -505,158 +478,9 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
505
478
|
if (!tree) {
|
|
506
479
|
return;
|
|
507
480
|
}
|
|
508
|
-
|
|
509
|
-
const [name, extension] = fileSplit(node.data.name);
|
|
510
|
-
const duplicateName = `${name}_copy${extension}`;
|
|
511
|
-
|
|
512
|
-
await tree.copy(node.id, duplicateName);
|
|
481
|
+
await tree.copy(node.id, makeDuplicateName(node.data.name));
|
|
513
482
|
});
|
|
514
483
|
|
|
515
|
-
const renderActions = () => {
|
|
516
|
-
const ic = MENU_ITEM_ICON_CLASS;
|
|
517
|
-
return (
|
|
518
|
-
<DropdownMenuContent
|
|
519
|
-
align="end"
|
|
520
|
-
className="print:hidden w-[220px]"
|
|
521
|
-
onClick={(e) => e.stopPropagation()}
|
|
522
|
-
onCloseAutoFocus={(e) => e.preventDefault()}
|
|
523
|
-
>
|
|
524
|
-
{!node.data.isDirectory && (
|
|
525
|
-
<DropdownMenuItem onSelect={() => node.select()}>
|
|
526
|
-
<ViewIcon className={ic} />
|
|
527
|
-
Open file
|
|
528
|
-
</DropdownMenuItem>
|
|
529
|
-
)}
|
|
530
|
-
{!node.data.isDirectory && !isWasm() && (
|
|
531
|
-
<DropdownMenuItem
|
|
532
|
-
onSelect={() => {
|
|
533
|
-
openFile({ path: node.data.path });
|
|
534
|
-
}}
|
|
535
|
-
>
|
|
536
|
-
<ExternalLinkIcon className={ic} />
|
|
537
|
-
Open file in external editor
|
|
538
|
-
</DropdownMenuItem>
|
|
539
|
-
)}
|
|
540
|
-
{node.data.isDirectory && (
|
|
541
|
-
<>
|
|
542
|
-
<DropdownMenuItem onSelect={() => handleCreateNotebook()}>
|
|
543
|
-
<MarimoPlusIcon className={ic} />
|
|
544
|
-
Create notebook
|
|
545
|
-
</DropdownMenuItem>
|
|
546
|
-
<DropdownMenuItem onSelect={() => handleCreateFile()}>
|
|
547
|
-
<FilePlus2Icon className={ic} />
|
|
548
|
-
Create file
|
|
549
|
-
</DropdownMenuItem>
|
|
550
|
-
<DropdownMenuItem onSelect={() => handleCreateFolder()}>
|
|
551
|
-
<FolderPlusIcon className={ic} />
|
|
552
|
-
Create folder
|
|
553
|
-
</DropdownMenuItem>
|
|
554
|
-
<DropdownMenuSeparator />
|
|
555
|
-
</>
|
|
556
|
-
)}
|
|
557
|
-
<DropdownMenuItem onSelect={() => node.edit()}>
|
|
558
|
-
<Edit3Icon className={ic} />
|
|
559
|
-
Rename
|
|
560
|
-
</DropdownMenuItem>
|
|
561
|
-
<DropdownMenuItem onSelect={handleDuplicate}>
|
|
562
|
-
<CopyIcon className={ic} />
|
|
563
|
-
Duplicate
|
|
564
|
-
</DropdownMenuItem>
|
|
565
|
-
<DropdownMenuItem
|
|
566
|
-
onSelect={async () => {
|
|
567
|
-
await copyToClipboard(node.data.path);
|
|
568
|
-
toast({ title: "Copied to clipboard" });
|
|
569
|
-
}}
|
|
570
|
-
>
|
|
571
|
-
<ListTreeIcon className={ic} />
|
|
572
|
-
Copy path
|
|
573
|
-
</DropdownMenuItem>
|
|
574
|
-
{tree && (
|
|
575
|
-
<DropdownMenuItem
|
|
576
|
-
onSelect={async () => {
|
|
577
|
-
await copyToClipboard(
|
|
578
|
-
tree.relativeFromRoot(node.data.path as FilePath),
|
|
579
|
-
);
|
|
580
|
-
toast({ title: "Copied to clipboard" });
|
|
581
|
-
}}
|
|
582
|
-
>
|
|
583
|
-
<ListTreeIcon className={ic} />
|
|
584
|
-
Copy relative path
|
|
585
|
-
</DropdownMenuItem>
|
|
586
|
-
)}
|
|
587
|
-
<DropdownMenuSeparator />
|
|
588
|
-
|
|
589
|
-
<DropdownMenuItem
|
|
590
|
-
onSelect={() => {
|
|
591
|
-
const { path } = node.data;
|
|
592
|
-
const pythonCode = PYTHON_CODE_FOR_FILE_TYPE[fileType](path);
|
|
593
|
-
handleInsertCode(pythonCode);
|
|
594
|
-
}}
|
|
595
|
-
>
|
|
596
|
-
<BetweenHorizontalStartIcon className={ic} />
|
|
597
|
-
Insert snippet for reading file
|
|
598
|
-
</DropdownMenuItem>
|
|
599
|
-
<DropdownMenuItem
|
|
600
|
-
onSelect={async () => {
|
|
601
|
-
toast({
|
|
602
|
-
title: "Copied to clipboard",
|
|
603
|
-
description:
|
|
604
|
-
"Code to open the file has been copied to your clipboard. You can also drag and drop this file into the editor",
|
|
605
|
-
});
|
|
606
|
-
const { path } = node.data;
|
|
607
|
-
const pythonCode = PYTHON_CODE_FOR_FILE_TYPE[fileType](path);
|
|
608
|
-
await copyToClipboard(pythonCode);
|
|
609
|
-
}}
|
|
610
|
-
>
|
|
611
|
-
<BracesIcon className={ic} />
|
|
612
|
-
Copy snippet for reading file
|
|
613
|
-
</DropdownMenuItem>
|
|
614
|
-
{/* Not shown in WASM */}
|
|
615
|
-
{node.data.isMarimoFile && !isWasm() && (
|
|
616
|
-
<>
|
|
617
|
-
<DropdownMenuSeparator />
|
|
618
|
-
<DropdownMenuItem onSelect={handleOpenMarimoFile}>
|
|
619
|
-
<PlaySquareIcon className={ic} />
|
|
620
|
-
Open notebook
|
|
621
|
-
</DropdownMenuItem>
|
|
622
|
-
</>
|
|
623
|
-
)}
|
|
624
|
-
<DropdownMenuSeparator />
|
|
625
|
-
{!node.data.isDirectory && !disableFileDownloads && (
|
|
626
|
-
<>
|
|
627
|
-
<DropdownMenuItem
|
|
628
|
-
onSelect={async () => {
|
|
629
|
-
const details = await sendFileDetails({ path: node.data.path });
|
|
630
|
-
if (details.isBase64 && details.contents) {
|
|
631
|
-
const blob = deserializeBlob(
|
|
632
|
-
base64ToDataURL(
|
|
633
|
-
details.contents as Base64String,
|
|
634
|
-
details.mimeType || "application/octet-stream",
|
|
635
|
-
),
|
|
636
|
-
);
|
|
637
|
-
downloadBlob(blob, node.data.name);
|
|
638
|
-
} else {
|
|
639
|
-
downloadBlob(
|
|
640
|
-
new Blob([details.contents || ""]),
|
|
641
|
-
node.data.name,
|
|
642
|
-
);
|
|
643
|
-
}
|
|
644
|
-
}}
|
|
645
|
-
>
|
|
646
|
-
<DownloadIcon className={ic} />
|
|
647
|
-
Download
|
|
648
|
-
</DropdownMenuItem>
|
|
649
|
-
<DropdownMenuSeparator />
|
|
650
|
-
</>
|
|
651
|
-
)}
|
|
652
|
-
<DropdownMenuItem onSelect={handleDeleteFile} variant="danger">
|
|
653
|
-
<Trash2Icon className={ic} />
|
|
654
|
-
Delete
|
|
655
|
-
</DropdownMenuItem>
|
|
656
|
-
</DropdownMenuContent>
|
|
657
|
-
);
|
|
658
|
-
};
|
|
659
|
-
|
|
660
484
|
return (
|
|
661
485
|
<div
|
|
662
486
|
style={style}
|
|
@@ -690,23 +514,138 @@ const Node = ({ node, style, dragHandle }: NodeRendererProps<FileInfo>) => {
|
|
|
690
514
|
/>
|
|
691
515
|
)}
|
|
692
516
|
{node.isEditing ? (
|
|
693
|
-
<
|
|
517
|
+
<FileNameInput node={node} />
|
|
694
518
|
) : (
|
|
695
519
|
<Show node={node} onOpenMarimoFile={handleOpenMarimoFile} />
|
|
696
520
|
)}
|
|
697
|
-
<
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
521
|
+
<FileActionsDropdown
|
|
522
|
+
testId="file-explorer-more-button"
|
|
523
|
+
iconClassName="w-5 h-5"
|
|
524
|
+
>
|
|
525
|
+
{!node.data.isDirectory && (
|
|
526
|
+
<DropdownMenuItem onSelect={() => node.select()}>
|
|
527
|
+
<ViewIcon className={MENU_ITEM_ICON_CLASS} />
|
|
528
|
+
Open file
|
|
529
|
+
</DropdownMenuItem>
|
|
530
|
+
)}
|
|
531
|
+
{!node.data.isDirectory && !isWasm() && (
|
|
532
|
+
<DropdownMenuItem
|
|
533
|
+
onSelect={() => {
|
|
534
|
+
openFile({ path: node.data.path });
|
|
535
|
+
}}
|
|
536
|
+
>
|
|
537
|
+
<ExternalLinkIcon className={MENU_ITEM_ICON_CLASS} />
|
|
538
|
+
Open file in external editor
|
|
539
|
+
</DropdownMenuItem>
|
|
540
|
+
)}
|
|
541
|
+
{node.data.isDirectory && (
|
|
542
|
+
<>
|
|
543
|
+
<DropdownMenuItem onSelect={() => handleCreateNotebook()}>
|
|
544
|
+
<MarimoPlusIcon className={MENU_ITEM_ICON_CLASS} />
|
|
545
|
+
Create notebook
|
|
546
|
+
</DropdownMenuItem>
|
|
547
|
+
<DropdownMenuItem onSelect={() => handleCreateFile()}>
|
|
548
|
+
<FilePlus2Icon className={MENU_ITEM_ICON_CLASS} />
|
|
549
|
+
Create file
|
|
550
|
+
</DropdownMenuItem>
|
|
551
|
+
<DropdownMenuItem onSelect={() => handleCreateFolder()}>
|
|
552
|
+
<FolderPlusIcon className={MENU_ITEM_ICON_CLASS} />
|
|
553
|
+
Create folder
|
|
554
|
+
</DropdownMenuItem>
|
|
555
|
+
<DropdownMenuSeparator />
|
|
556
|
+
</>
|
|
557
|
+
)}
|
|
558
|
+
<RenameMenuItem onSelect={() => node.edit()} />
|
|
559
|
+
<DuplicateMenuItem onSelect={handleDuplicate} />
|
|
560
|
+
<DropdownMenuItem
|
|
561
|
+
onSelect={async () => {
|
|
562
|
+
await copyToClipboard(node.data.path);
|
|
563
|
+
toast({ title: "Copied to clipboard" });
|
|
564
|
+
}}
|
|
702
565
|
>
|
|
703
|
-
<
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
566
|
+
<ListTreeIcon className={MENU_ITEM_ICON_CLASS} />
|
|
567
|
+
Copy path
|
|
568
|
+
</DropdownMenuItem>
|
|
569
|
+
{tree && (
|
|
570
|
+
<DropdownMenuItem
|
|
571
|
+
onSelect={async () => {
|
|
572
|
+
await copyToClipboard(
|
|
573
|
+
tree.relativeFromRoot(node.data.path as FilePath),
|
|
574
|
+
);
|
|
575
|
+
toast({ title: "Copied to clipboard" });
|
|
576
|
+
}}
|
|
577
|
+
>
|
|
578
|
+
<ListTreeIcon className={MENU_ITEM_ICON_CLASS} />
|
|
579
|
+
Copy relative path
|
|
580
|
+
</DropdownMenuItem>
|
|
581
|
+
)}
|
|
582
|
+
<DropdownMenuSeparator />
|
|
583
|
+
<DropdownMenuItem
|
|
584
|
+
onSelect={() => {
|
|
585
|
+
const { path } = node.data;
|
|
586
|
+
const pythonCode = PYTHON_CODE_FOR_FILE_TYPE[fileType](path);
|
|
587
|
+
handleInsertCode(pythonCode);
|
|
588
|
+
}}
|
|
589
|
+
>
|
|
590
|
+
<BetweenHorizontalStartIcon className={MENU_ITEM_ICON_CLASS} />
|
|
591
|
+
Insert snippet for reading file
|
|
592
|
+
</DropdownMenuItem>
|
|
593
|
+
<DropdownMenuItem
|
|
594
|
+
onSelect={async () => {
|
|
595
|
+
toast({
|
|
596
|
+
title: "Copied to clipboard",
|
|
597
|
+
description:
|
|
598
|
+
"Code to open the file has been copied to your clipboard. You can also drag and drop this file into the editor",
|
|
599
|
+
});
|
|
600
|
+
const { path } = node.data;
|
|
601
|
+
const pythonCode = PYTHON_CODE_FOR_FILE_TYPE[fileType](path);
|
|
602
|
+
await copyToClipboard(pythonCode);
|
|
603
|
+
}}
|
|
604
|
+
>
|
|
605
|
+
<BracesIcon className={MENU_ITEM_ICON_CLASS} />
|
|
606
|
+
Copy snippet for reading file
|
|
607
|
+
</DropdownMenuItem>
|
|
608
|
+
{node.data.isMarimoFile && !isWasm() && (
|
|
609
|
+
<>
|
|
610
|
+
<DropdownMenuSeparator />
|
|
611
|
+
<DropdownMenuItem onSelect={handleOpenMarimoFile}>
|
|
612
|
+
<PlaySquareIcon className={MENU_ITEM_ICON_CLASS} />
|
|
613
|
+
Open notebook
|
|
614
|
+
</DropdownMenuItem>
|
|
615
|
+
</>
|
|
616
|
+
)}
|
|
617
|
+
<DropdownMenuSeparator />
|
|
618
|
+
{!node.data.isDirectory && !disableFileDownloads && (
|
|
619
|
+
<>
|
|
620
|
+
<DropdownMenuItem
|
|
621
|
+
onSelect={async () => {
|
|
622
|
+
const details = await sendFileDetails({
|
|
623
|
+
path: node.data.path,
|
|
624
|
+
});
|
|
625
|
+
if (details.isBase64 && details.contents) {
|
|
626
|
+
const blob = deserializeBlob(
|
|
627
|
+
base64ToDataURL(
|
|
628
|
+
details.contents as Base64String,
|
|
629
|
+
details.mimeType || "application/octet-stream",
|
|
630
|
+
),
|
|
631
|
+
);
|
|
632
|
+
downloadBlob(blob, node.data.name);
|
|
633
|
+
} else {
|
|
634
|
+
downloadBlob(
|
|
635
|
+
new Blob([details.contents || ""]),
|
|
636
|
+
node.data.name,
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
}}
|
|
640
|
+
>
|
|
641
|
+
<DownloadIcon className={MENU_ITEM_ICON_CLASS} />
|
|
642
|
+
Download
|
|
643
|
+
</DropdownMenuItem>
|
|
644
|
+
<DropdownMenuSeparator />
|
|
645
|
+
</>
|
|
646
|
+
)}
|
|
647
|
+
<DeleteMenuItem onSelect={handleDeleteFile} />
|
|
648
|
+
</FileActionsDropdown>
|
|
710
649
|
</span>
|
|
711
650
|
</div>
|
|
712
651
|
);
|