@marimo-team/islands 0.23.10-dev15 → 0.23.10-dev17

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.
@@ -35274,7 +35274,7 @@ ${d}`,
35274
35274
  return Logger.warn("Failed to get version from mount config"), null;
35275
35275
  }
35276
35276
  }
35277
- marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.10-dev15");
35277
+ marimoVersionAtom = atom(getVersionFromMountConfig() || "0.23.10-dev17");
35278
35278
  showCodeInRunModeAtom = atom(true);
35279
35279
  atom(null);
35280
35280
  var import_compiler_runtime = require_compiler_runtime();
package/dist/main.js CHANGED
@@ -26,7 +26,7 @@ import { $ as useCellActions, An as LoaderCircle, At as DeferredRequestRegistry,
26
26
  import { __tla as __tla_1 } from "./chunk-5FQGJX7Z-BNjes6Yx.js";
27
27
  import { o as useSize, s as Root$2, u as createLucideIcon } from "./dist-C1BYNeCR.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-B96zNUEA.js";
29
- import { $ as TableBody, $t as ChevronLeft, A as ComboboxItem, At as ChartErrorState, B as contextAwarePanelOpen, Bt as $fae977aafc393c5c$export$6b862160d295c8e, C as prettifyRowColumnCount, Ct as dateToLocalISODate, D as DatePicker, Dt as TabsContent, E as useInternalStateWithSync, Et as Tabs, F as CommandList, Ft as RenderTextWithLinks, G as slotsController, H as contextAwarePanelType, Ht as GripHorizontal, I as CommandSeparator, It as Kbd, Jt as Code, K as Toggle, Kt as Ellipsis, L as smartMatch, Lt as HtmlOutput, M as CommandEmpty, Mt as ChartLoadingState, N as CommandInput, Nt as LazyVegaEmbed, O as DateRangePicker, Ot as TabsList, P as CommandItem, Pt as useOverflowDetection, Q as Table, Qt as ChevronsDownUp, R as ContextAwarePanelItem, Rt as EmotionCacheProvider, S as downloadSizeLimitAtom, St as Maps, T as getColumnCountForDisplay, Tt as dateToLocalISOTime, U as isCellAwareAtom, Ut as Funnel, V as contextAwarePanelOwner, Vt as TextWrap, W as SlotNames, Wt as EyeOff, X as Fill, Xt as ChevronsRight, Yt as ChevronsUpDown, Z as Provider$1, Zt as ChevronsLeft, _ as downloadBlob, _t as SELECT_COLUMN_ID, at as generateColumns, b as Progress, bt as getMimeValues, c as Slide, ct as ColumnChartContext, d as JsonOutput, dt as useIntersectionObserver, en as ArrowDownWideNarrow, et as TableCell, f as OutputArea, ft as usePrevious$1, g as ADD_PRINTING_CLASS, gt as INDEX_COLUMN_NAME, h as InstallPackageButton, ht as loadTableData, it as NAMELESS_COLUMN_PREFIX, j as Command, jt as ChartInfoState, k as Combobox, kt as TabsTrigger, l as RadioGroup, lt as ColumnChartSpecModel, m as DataTable, mt as loadTableAndRawData, n as marimoVersionAtom, nt as TableHeader, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as inferFieldTypes, p as OutputRenderer, pt as getPageIndexForRow, qt as Download, r as showCodeInRunModeAtom, rt as TableRow, st as renderCellValue, t as useNotebookCodeAvailable, tt as TableHead, u as RadioGroupItem, ut as DelayMount, v as downloadByURL, vt as TOO_MANY_ROWS, w as prettifyRowCount, wt as dateToLocalISODateTime, x as Filenames, xt as isNullishFilter, y as downloadHTMLAsImage, yt as toFieldTypes, z as PANEL_TYPES, zt as $fae977aafc393c5c$export$588937bcd60ade55, __tla as __tla_2 } from "./code-visibility-QvdSqBSm.js";
29
+ import { $ as TableBody, $t as ChevronLeft, A as ComboboxItem, At as ChartErrorState, B as contextAwarePanelOpen, Bt as $fae977aafc393c5c$export$6b862160d295c8e, C as prettifyRowColumnCount, Ct as dateToLocalISODate, D as DatePicker, Dt as TabsContent, E as useInternalStateWithSync, Et as Tabs, F as CommandList, Ft as RenderTextWithLinks, G as slotsController, H as contextAwarePanelType, Ht as GripHorizontal, I as CommandSeparator, It as Kbd, Jt as Code, K as Toggle, Kt as Ellipsis, L as smartMatch, Lt as HtmlOutput, M as CommandEmpty, Mt as ChartLoadingState, N as CommandInput, Nt as LazyVegaEmbed, O as DateRangePicker, Ot as TabsList, P as CommandItem, Pt as useOverflowDetection, Q as Table, Qt as ChevronsDownUp, R as ContextAwarePanelItem, Rt as EmotionCacheProvider, S as downloadSizeLimitAtom, St as Maps, T as getColumnCountForDisplay, Tt as dateToLocalISOTime, U as isCellAwareAtom, Ut as Funnel, V as contextAwarePanelOwner, Vt as TextWrap, W as SlotNames, Wt as EyeOff, X as Fill, Xt as ChevronsRight, Yt as ChevronsUpDown, Z as Provider$1, Zt as ChevronsLeft, _ as downloadBlob, _t as SELECT_COLUMN_ID, at as generateColumns, b as Progress, bt as getMimeValues, c as Slide, ct as ColumnChartContext, d as JsonOutput, dt as useIntersectionObserver, en as ArrowDownWideNarrow, et as TableCell, f as OutputArea, ft as usePrevious$1, g as ADD_PRINTING_CLASS, gt as INDEX_COLUMN_NAME, h as InstallPackageButton, ht as loadTableData, it as NAMELESS_COLUMN_PREFIX, j as Command, jt as ChartInfoState, k as Combobox, kt as TabsTrigger, l as RadioGroup, lt as ColumnChartSpecModel, m as DataTable, mt as loadTableAndRawData, n as marimoVersionAtom, nt as TableHeader, o as SLIDE_TYPE_OPTIONS_BY_VALUE, ot as inferFieldTypes, p as OutputRenderer, pt as getPageIndexForRow, qt as Download, r as showCodeInRunModeAtom, rt as TableRow, st as renderCellValue, t as useNotebookCodeAvailable, tt as TableHead, u as RadioGroupItem, ut as DelayMount, v as downloadByURL, vt as TOO_MANY_ROWS, w as prettifyRowCount, wt as dateToLocalISODateTime, x as Filenames, xt as isNullishFilter, y as downloadHTMLAsImage, yt as toFieldTypes, z as PANEL_TYPES, zt as $fae977aafc393c5c$export$588937bcd60ade55, __tla as __tla_2 } from "./code-visibility-D80f1Ibv.js";
30
30
  import { c as Calendar, i as createReducerAndAtoms, n as useOnUnmount, o as ToggleLeft, t as useOnMount } from "./useLifecycle-BBO9PIph.js";
31
31
  import { t as Check } from "./check-DTbrK0zt.js";
32
32
  import { A as Trigger$1, C as $a916eb452884faea$export$b7a616150fdb9f44, 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, 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, x as assertNever } from "./strings-Bu3vlb6W.js";
@@ -36116,7 +36116,7 @@ ${c}
36116
36116
  if (l && l !== "slide") return l;
36117
36117
  if (c == null ? void 0 : c.has(e)) return "skip";
36118
36118
  }
36119
- var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-qiH93aYL.js"));
36119
+ var LazySlidesComponent = import_react.lazy(() => import("./reveal-component-mUdfwXMF.js"));
36120
36120
  const SlidesLayoutRenderer = ({ layout: e, setLayout: r, cells: c, mode: l }) => {
36121
36121
  var _a3;
36122
36122
  let u = useAtomValue(kioskModeAtom), d = l === "read" || u, f = useAtomValue(numColumnsAtom) > 1, [p, m] = (0, import_react.useState)(null), { slideCells: h, skippedIds: g, noOutputIds: _, slideTypes: v, startCellIndex: y } = (0, import_react.useMemo)(() => computeSlideCellsInfo(c, e), [
@@ -9,7 +9,7 @@ import { t as require_compiler_runtime } from "./compiler-runtime-CEbnTgxf.js";
9
9
  import { ct as kioskModeAtom } from "./html-to-image-BqJ4c852.js";
10
10
  import "./chunk-5FQGJX7Z-BNjes6Yx.js";
11
11
  import { u as createLucideIcon } from "./dist-C1BYNeCR.js";
12
- import { Gt as Expand, J as PanelGroup, Jt as Code, Wt as EyeOff, Y as PanelResizeHandle, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, q as Panel, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-QvdSqBSm.js";
12
+ import { Gt as Expand, J as PanelGroup, Jt as Code, Wt as EyeOff, Y as PanelResizeHandle, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, q as Panel, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-D80f1Ibv.js";
13
13
  import { q as useDebouncedCallback } from "./input-_2sjvfne.js";
14
14
  import "./toDate-x-WRDCH7.js";
15
15
  import "./react-dom-BTJzcVJ9.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.23.10-dev15",
3
+ "version": "0.23.10-dev17",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -3,18 +3,15 @@
3
3
  import { CommandList } from "cmdk";
4
4
  import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
5
5
  import { atomWithStorage } from "jotai/utils";
6
- import {
7
- EyeIcon,
8
- EyeOffIcon,
9
- PlusIcon,
10
- PlusSquareIcon,
11
- XIcon,
12
- } from "lucide-react";
6
+ import { PlusIcon, PlusSquareIcon, XIcon } from "lucide-react";
13
7
  import React from "react";
14
8
  import { dbDisplayName } from "@/components/databases/display";
15
9
  import { EngineVariable } from "@/components/databases/engine-variable";
16
10
  import { DatabaseLogo } from "@/components/databases/icon";
17
- import { RefreshIconButton } from "@/components/editor/file-tree/tree-actions";
11
+ import {
12
+ RefreshIconButton,
13
+ VisibilityToggleButton,
14
+ } from "@/components/editor/file-tree/tree-actions";
18
15
  import { CopyClipboardIcon } from "@/components/icons/copy-icon";
19
16
  import { Button } from "@/components/ui/button";
20
17
  import { Command, CommandInput, CommandItem } from "@/components/ui/command";
@@ -286,27 +283,15 @@ export const DataSources: React.FC = () => {
286
283
  </button>
287
284
  )}
288
285
 
289
- <Tooltip
290
- content={
291
- hideEmpty
292
- ? "Show empty schemas and databases"
293
- : "Hide empty schemas and databases"
294
- }
295
- >
296
- <Button
297
- data-testid="datasources-hide-empty-button"
298
- variant="ghost"
299
- size="sm"
300
- className="px-2 rounded-none focus-visible:outline-hidden"
301
- onClick={() => setHideEmpty(!hideEmpty)}
302
- >
303
- {hideEmpty ? (
304
- <EyeOffIcon className="h-4 w-4" />
305
- ) : (
306
- <EyeIcon className="h-4 w-4" />
307
- )}
308
- </Button>
309
- </Tooltip>
286
+ <VisibilityToggleButton
287
+ data-testid="datasources-hide-empty-button"
288
+ isVisible={!hideEmpty}
289
+ onToggle={() => setHideEmpty(!hideEmpty)}
290
+ showTooltip="Show empty schemas and databases"
291
+ hideTooltip="Hide empty schemas and databases"
292
+ size="sm"
293
+ className="px-2 rounded-none focus-visible:outline-hidden"
294
+ />
310
295
 
311
296
  <AddConnectionDialog>
312
297
  <Button
@@ -9,8 +9,6 @@ import {
9
9
  CopyMinusIcon,
10
10
  DownloadIcon,
11
11
  ExternalLinkIcon,
12
- EyeIcon,
13
- EyeOffIcon,
14
12
  FilePlus2Icon,
15
13
  FolderPlusIcon,
16
14
  ListTreeIcon,
@@ -43,6 +41,7 @@ import {
43
41
  MENU_ITEM_ICON_CLASS,
44
42
  RefreshIconButton,
45
43
  TreeChevron,
44
+ VisibilityToggleButton,
46
45
  } from "@/components/editor/file-tree/tree-actions";
47
46
  import { MarimoIcon, MarimoPlusIcon } from "@/components/icons/marimo-icons";
48
47
  import { Spinner } from "@/components/icons/spinner";
@@ -338,22 +337,13 @@ const Toolbar = ({
338
337
  data-testid="file-explorer-refresh-button"
339
338
  onClick={onRefresh}
340
339
  />
341
- <Tooltip
342
- content={showHiddenFiles ? "Hide hidden files" : "Show hidden files"}
343
- >
344
- <Button
345
- data-testid="file-explorer-hidden-files-button"
346
- onClick={onHidden}
347
- variant="text"
348
- size="xs"
349
- >
350
- {showHiddenFiles ? (
351
- <EyeIcon size={16} className="text-primary" />
352
- ) : (
353
- <EyeOffIcon size={16} />
354
- )}
355
- </Button>
356
- </Tooltip>
340
+ <VisibilityToggleButton
341
+ data-testid="file-explorer-hidden-files-button"
342
+ isVisible={showHiddenFiles}
343
+ onToggle={onHidden}
344
+ showTooltip="Show hidden files"
345
+ hideTooltip="Hide hidden files"
346
+ />
357
347
  <Tooltip content="Collapse all folders">
358
348
  <Button
359
349
  data-testid="file-explorer-collapse-button"
@@ -2,11 +2,13 @@
2
2
 
3
3
  import {
4
4
  ChevronRightIcon,
5
+ EyeIcon,
6
+ EyeOffIcon,
5
7
  MoreVerticalIcon,
6
8
  RefreshCwIcon,
7
9
  } from "lucide-react";
8
10
  import React, { useCallback, useState } from "react";
9
- import { Button } from "@/components/ui/button";
11
+ import { Button, type ButtonProps } from "@/components/ui/button";
10
12
  import { Tooltip } from "@/components/ui/tooltip";
11
13
  import { cn } from "@/utils/cn";
12
14
 
@@ -73,6 +75,51 @@ export const RefreshIconButton: React.FC<{
73
75
  return <Tooltip content={tooltip}>{button}</Tooltip>;
74
76
  };
75
77
 
78
+ /**
79
+ * Toggle button that switches between an eye (visible) and crossed-out eye
80
+ * (hidden) icon. Used to show/hide optional items in toolbars, e.g. hidden
81
+ * files in the file explorer or empty schemas in the data sources panel.
82
+ */
83
+ export const VisibilityToggleButton: React.FC<{
84
+ /** Whether the optional items are currently visible. */
85
+ isVisible: boolean;
86
+ onToggle: () => void;
87
+ /** Tooltip shown while items are hidden (clicking will show them). */
88
+ showTooltip: string;
89
+ /** Tooltip shown while items are visible (clicking will hide them). */
90
+ hideTooltip: string;
91
+ size?: ButtonProps["size"];
92
+ className?: string;
93
+ iconClassName?: string;
94
+ "data-testid"?: string;
95
+ }> = ({
96
+ isVisible,
97
+ onToggle,
98
+ showTooltip,
99
+ hideTooltip,
100
+ size = "xs",
101
+ className,
102
+ iconClassName,
103
+ "data-testid": dataTestId,
104
+ }) => {
105
+ const Icon = isVisible ? EyeIcon : EyeOffIcon;
106
+ return (
107
+ <Tooltip content={isVisible ? hideTooltip : showTooltip}>
108
+ <Button
109
+ data-testid={dataTestId}
110
+ variant="text"
111
+ size={size}
112
+ className={className}
113
+ onClick={onToggle}
114
+ >
115
+ <Icon
116
+ className={cn("h-4 w-4", isVisible && "text-primary", iconClassName)}
117
+ />
118
+ </Button>
119
+ </Tooltip>
120
+ );
121
+ };
122
+
76
123
  /**
77
124
  * Three-dot menu trigger that fades in on row hover.
78
125
  * Must be inside a `group` container.
@@ -0,0 +1,55 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import { describe, expect, it } from "vitest";
3
+ import type { StorageEntry } from "@/core/storage/types";
4
+ import { exportedForTesting } from "../storage-inspector";
5
+
6
+ const { storageEntryKey } = exportedForTesting;
7
+
8
+ function makeEntry(
9
+ overrides: Partial<StorageEntry> & { path: string },
10
+ ): StorageEntry {
11
+ return {
12
+ kind: overrides.kind ?? "file",
13
+ lastModified: overrides.lastModified ?? null,
14
+ metadata: overrides.metadata ?? {},
15
+ path: overrides.path,
16
+ size: overrides.size ?? 0,
17
+ };
18
+ }
19
+
20
+ describe("storageEntryKey", () => {
21
+ it("prefers the backend id when present (e.g. Google Drive)", () => {
22
+ const entry = makeEntry({
23
+ path: "Data Resume.pdf",
24
+ metadata: { id: "drive-file-id-123" },
25
+ });
26
+ // Two files can share a path on Drive; the id keeps keys unique.
27
+ expect(storageEntryKey(entry, 0)).toBe("drive-file-id-123");
28
+ expect(storageEntryKey(entry, 4)).toBe("drive-file-id-123");
29
+ });
30
+
31
+ it("falls back to path + index when there is no id", () => {
32
+ const entry = makeEntry({ path: "Data Resume.pdf" });
33
+ expect(storageEntryKey(entry, 0)).toBe("Data Resume.pdf::0");
34
+ expect(storageEntryKey(entry, 4)).toBe("Data Resume.pdf::4");
35
+ });
36
+
37
+ it("keeps duplicate-path entries unique via the index fallback", () => {
38
+ const entries = [
39
+ makeEntry({ path: "Data Resume.pdf" }),
40
+ makeEntry({ path: "Data Resume.pdf" }),
41
+ makeEntry({ path: "Data Resume.pdf" }),
42
+ ];
43
+ const keys = entries.map((entry, index) => storageEntryKey(entry, index));
44
+ expect(new Set(keys).size).toBe(entries.length);
45
+ });
46
+
47
+ it("ignores a non-string or empty id", () => {
48
+ expect(
49
+ storageEntryKey(makeEntry({ path: "a.pdf", metadata: { id: "" } }), 2),
50
+ ).toBe("a.pdf::2");
51
+ expect(
52
+ storageEntryKey(makeEntry({ path: "a.pdf", metadata: { id: 5 } }), 2),
53
+ ).toBe("a.pdf::2");
54
+ });
55
+ });
@@ -94,6 +94,18 @@ function displayName(path: string): string {
94
94
  return parts[parts.length - 1] || trimmed;
95
95
  }
96
96
 
97
+ /**
98
+ * Stable, unique identity for an entry row. Prefer the
99
+ * backend's stable id when present and fall back to the list index
100
+ */
101
+ function storageEntryKey(entry: StorageEntry, index: number): string {
102
+ const id = entry.metadata?.id;
103
+ if (typeof id === "string" && id.length > 0) {
104
+ return id;
105
+ }
106
+ return `${entry.path}::${index}`;
107
+ }
108
+
97
109
  /**
98
110
  * Recursively check whether an entry (or any of its loaded descendants)
99
111
  * matches the search query.
@@ -213,26 +225,31 @@ const StorageEntryChildren: React.FC<{
213
225
 
214
226
  return (
215
227
  <>
216
- {filtered.map((child) => (
217
- <StorageEntryRow
218
- key={child.path}
219
- entry={child}
220
- namespace={namespace}
221
- protocol={protocol}
222
- rootPath={rootPath}
223
- backendType={backendType}
224
- depth={depth}
225
- locale={locale}
226
- searchValue={searchValue}
227
- onOpenFile={onOpenFile}
228
- />
229
- ))}
228
+ {filtered.map((child) => {
229
+ const rowKey = storageEntryKey(child, children.indexOf(child));
230
+ return (
231
+ <StorageEntryRow
232
+ key={rowKey}
233
+ rowKey={rowKey}
234
+ entry={child}
235
+ namespace={namespace}
236
+ protocol={protocol}
237
+ rootPath={rootPath}
238
+ backendType={backendType}
239
+ depth={depth}
240
+ locale={locale}
241
+ searchValue={searchValue}
242
+ onOpenFile={onOpenFile}
243
+ />
244
+ );
245
+ })}
230
246
  </>
231
247
  );
232
248
  };
233
249
 
234
250
  const StorageEntryRow: React.FC<{
235
251
  entry: StorageEntry;
252
+ rowKey: string;
236
253
  namespace: string;
237
254
  protocol: string;
238
255
  rootPath: string;
@@ -243,6 +260,7 @@ const StorageEntryRow: React.FC<{
243
260
  onOpenFile: (info: OpenFileInfo) => void;
244
261
  }> = ({
245
262
  entry,
263
+ rowKey,
246
264
  namespace,
247
265
  protocol,
248
266
  rootPath,
@@ -312,7 +330,7 @@ const StorageEntryRow: React.FC<{
312
330
  isDir && "font-medium",
313
331
  )}
314
332
  style={indentStyle(depth)}
315
- value={`${namespace}:${entry.path}`}
333
+ value={`${namespace}:${rowKey}`}
316
334
  onSelect={() => {
317
335
  if (isDir) {
318
336
  setIsExpanded(!effectiveExpanded);
@@ -525,20 +543,24 @@ const StorageNamespaceSection: React.FC<{
525
543
  No matches
526
544
  </div>
527
545
  )}
528
- {filtered.map((entry) => (
529
- <StorageEntryRow
530
- key={entry.path}
531
- entry={entry}
532
- namespace={namespaceName}
533
- protocol={namespace.protocol}
534
- rootPath={namespace.rootPath}
535
- backendType={namespace.backendType}
536
- depth={1}
537
- locale={locale}
538
- searchValue={searchValue}
539
- onOpenFile={onOpenFile}
540
- />
541
- ))}
546
+ {filtered.map((entry) => {
547
+ const rowKey = storageEntryKey(entry, entries.indexOf(entry));
548
+ return (
549
+ <StorageEntryRow
550
+ key={rowKey}
551
+ rowKey={rowKey}
552
+ entry={entry}
553
+ namespace={namespaceName}
554
+ protocol={namespace.protocol}
555
+ rootPath={namespace.rootPath}
556
+ backendType={namespace.backendType}
557
+ depth={1}
558
+ locale={locale}
559
+ searchValue={searchValue}
560
+ onOpenFile={onOpenFile}
561
+ />
562
+ );
563
+ })}
542
564
  </>
543
565
  )}
544
566
  </>
@@ -652,3 +674,7 @@ export const StorageInspector: React.FC = () => {
652
674
  </div>
653
675
  );
654
676
  };
677
+
678
+ export const exportedForTesting = {
679
+ storageEntryKey,
680
+ };