@marimo-team/islands 0.21.2-dev93 → 0.21.2-dev95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Combination-BVnmMSzE.js → Combination-B--d1_LV.js} +8 -8
- package/dist/{ConnectedDataExplorerComponent-BzRetIpL.js → ConnectedDataExplorerComponent-CTfvzyMi.js} +19 -19
- package/dist/{any-language-editor-BgjMQ0JO.js → any-language-editor-Bj-3432h.js} +4 -4
- package/dist/{button-CxEhg2E1.js → button-qsiIHncQ.js} +10 -11
- package/dist/{capabilities-x7AvQTfX.js → capabilities-BC3mzKnw.js} +1 -1
- package/dist/{chat-ui-Blhe8Kd8.js → chat-ui-BvK3aDSR.js} +13 -13
- package/dist/{check-Cfbm1K98.js → check-D_YwHEgY.js} +1 -1
- package/dist/{copy-Bb-tO2YP.js → copy-CBo9JcJW.js} +2 -2
- package/dist/{dist-eWNxvDQG.js → dist-D2Rk1j4R.js} +2 -2
- package/dist/{error-banner-CW87Aylu.js → error-banner-DkDzvax3.js} +25 -25
- package/dist/{esm-BjPSZ7Qf.js → esm-C9_jY_wu.js} +4 -4
- package/dist/{glide-data-editor-CSemfq4D.js → glide-data-editor-D0IYL4_F.js} +7 -7
- package/dist/{input-EtKyRcb-.js → input-C5uUN4xL.js} +9 -9
- package/dist/{label-mQKeDCJ8.js → label-DwSVaniz.js} +4 -4
- package/dist/{loader-hvRcVSq5.js → loader-DrMJeyDu.js} +15 -15
- package/dist/main.js +17411 -17369
- package/dist/{mermaid-CjhFZReU.js → mermaid-Bwy7OYzI.js} +5 -5
- package/dist/{process-output-Cy0KEXJh.js → process-output-CT8hHGp6.js} +15 -15
- package/dist/{slides-component-DKg-ohoF.js → slides-component-BsaaAy66.js} +2 -2
- package/dist/{spec-DLNqef4y.js → spec-BLAZSydG.js} +3 -3
- package/dist/style.css +1 -1
- package/dist/{toDate-BEXAEQ0o.js → toDate-BWaG12Pv.js} +3 -3
- package/dist/{tooltip-CYv8qy5F.js → tooltip-DGHTbHl5.js} +3 -3
- package/dist/{types-B7Om6oxp.js → types-Dqw69fPc.js} +2 -2
- package/dist/{useAsyncData-b2IfqSIa.js → useAsyncData-Dqt2tV1E.js} +1 -1
- package/dist/{useDeepCompareMemoize-C7Ut95sA.js → useDeepCompareMemoize-D2PKDkrk.js} +4 -4
- package/dist/{useIframeCapabilities-DHGxPMu5.js → useIframeCapabilities-DlwLttZw.js} +1 -1
- package/dist/{useLifecycle-Q7CzdfPd.js → useLifecycle-CJ_5Z4Mk.js} +3 -3
- package/dist/{useTheme-5rRsavIK.js → useTheme-BIAKDAh6.js} +2 -2
- package/dist/{vega-component-B0Ik4707.js → vega-component-CTOT0vRO.js} +9 -9
- package/package.json +1 -1
- package/src/components/data-table/TableActions.tsx +26 -58
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +24 -13
- package/src/components/data-table/data-table.tsx +11 -11
- package/src/components/data-table/download-actions.tsx +18 -18
- package/src/components/data-table/hooks/use-panel-ownership.ts +15 -5
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +53 -44
- package/src/components/data-table/schemas.ts +7 -2
- package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +161 -0
- package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +16 -9
- package/src/core/slots/slots.ts +1 -0
- package/src/plugins/impl/DataTablePlugin.tsx +19 -26
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +0 -1
- package/src/stories/dataframe.stories.tsx +1 -1
|
@@ -12,16 +12,16 @@ import {
|
|
|
12
12
|
ChevronsLeft,
|
|
13
13
|
ChevronsRight,
|
|
14
14
|
Info,
|
|
15
|
-
SearchIcon,
|
|
16
15
|
} from "lucide-react";
|
|
17
|
-
import { useRef, useState } from "react";
|
|
16
|
+
import { type KeyboardEvent, useId, useRef, useState } from "react";
|
|
18
17
|
import { useLocale } from "react-aria";
|
|
19
18
|
import { ColumnName } from "@/components/datasources/components";
|
|
20
19
|
import { CopyClipboardIcon } from "@/components/icons/copy-icon";
|
|
21
20
|
import { Spinner } from "@/components/icons/spinner";
|
|
22
21
|
import { KeyboardHotkeys } from "@/components/shortcuts/renderShortcut";
|
|
23
22
|
import { Button } from "@/components/ui/button";
|
|
24
|
-
import {
|
|
23
|
+
import { Checkbox } from "@/components/ui/checkbox";
|
|
24
|
+
import { Command, CommandInput } from "@/components/ui/command";
|
|
25
25
|
import {
|
|
26
26
|
Table,
|
|
27
27
|
TableBody,
|
|
@@ -32,7 +32,6 @@ import {
|
|
|
32
32
|
} from "@/components/ui/table";
|
|
33
33
|
import { DelayMount } from "@/components/utils/delay-mount";
|
|
34
34
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
35
|
-
import { useKeydownOnElement } from "@/hooks/useHotkey";
|
|
36
35
|
import { Banner, ErrorBanner } from "@/plugins/impl/common/error-banner";
|
|
37
36
|
import type { GetRowResult } from "@/plugins/impl/DataTablePlugin";
|
|
38
37
|
import { NAMELESS_COLUMN_PREFIX, renderCellValue } from "../columns";
|
|
@@ -68,7 +67,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
68
67
|
}: RowViewerPanelProps) => {
|
|
69
68
|
const [searchQuery, setSearchQuery] = useState("");
|
|
70
69
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
71
|
-
const
|
|
70
|
+
const checkboxId = useId();
|
|
72
71
|
const { locale } = useLocale();
|
|
73
72
|
|
|
74
73
|
const tooManyRows = totalRows === TOO_MANY_ROWS;
|
|
@@ -102,26 +101,29 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
102
101
|
setRow(totalRows - 1);
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
104
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
105
|
+
// Don't intercept keys when typing in an input
|
|
106
|
+
if (e.target instanceof HTMLInputElement) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
switch (e.key) {
|
|
110
|
+
case "ArrowLeft":
|
|
111
|
+
setRow(rowIdx - 1);
|
|
112
|
+
|
|
113
|
+
break;
|
|
114
|
+
|
|
115
|
+
case "ArrowRight":
|
|
116
|
+
setRow(rowIdx + 1);
|
|
117
|
+
|
|
118
|
+
break;
|
|
119
|
+
|
|
120
|
+
case " ":
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
toggleRowSelection();
|
|
123
|
+
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
125
127
|
|
|
126
128
|
const buttonStyles = "h-6 w-6 p-0.5";
|
|
127
129
|
|
|
@@ -248,19 +250,29 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
248
250
|
className="flex flex-col gap-3 mt-4 focus:outline-hidden"
|
|
249
251
|
ref={panelRef}
|
|
250
252
|
tabIndex={-1}
|
|
253
|
+
onKeyDown={handleKeyDown}
|
|
251
254
|
>
|
|
252
|
-
<div className="flex flex-row gap-2 items-center mr-2">
|
|
255
|
+
<div className="flex flex-row gap-2 items-center mr-2 px-2">
|
|
253
256
|
{isSelectable && (
|
|
254
|
-
<div
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
<div
|
|
258
|
+
className="flex items-center"
|
|
259
|
+
title="Select/unselect the current row"
|
|
260
|
+
>
|
|
261
|
+
<div className="flex items-center gap-1.5">
|
|
262
|
+
<Checkbox
|
|
263
|
+
id={checkboxId}
|
|
264
|
+
checked={isRowSelected}
|
|
265
|
+
onCheckedChange={toggleRowSelection}
|
|
266
|
+
className="h-3.5 w-3.5"
|
|
267
|
+
/>
|
|
268
|
+
<label
|
|
269
|
+
htmlFor={checkboxId}
|
|
270
|
+
className="text-xs text-muted-foreground cursor-pointer"
|
|
271
|
+
>
|
|
272
|
+
Select
|
|
273
|
+
</label>
|
|
274
|
+
</div>
|
|
275
|
+
<KeyboardHotkeys shortcut="Space" className="scale-75" />
|
|
264
276
|
</div>
|
|
265
277
|
)}
|
|
266
278
|
|
|
@@ -315,17 +327,14 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
315
327
|
</Button>
|
|
316
328
|
</div>
|
|
317
329
|
|
|
318
|
-
<
|
|
319
|
-
<
|
|
320
|
-
ref={searchInputRef}
|
|
321
|
-
type="text"
|
|
330
|
+
<Command className="bg-background" shouldFilter={false}>
|
|
331
|
+
<CommandInput
|
|
322
332
|
placeholder="Search"
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
className="mb-0 border-border"
|
|
333
|
+
value={searchQuery}
|
|
334
|
+
onValueChange={setSearchQuery}
|
|
326
335
|
data-testid="selection-panel-search-input"
|
|
327
336
|
/>
|
|
328
|
-
</
|
|
337
|
+
</Command>
|
|
329
338
|
{renderTable()}
|
|
330
339
|
</div>
|
|
331
340
|
);
|
|
@@ -5,7 +5,7 @@ import { rpc } from "@/plugins/core/rpc";
|
|
|
5
5
|
|
|
6
6
|
export type DownloadAsArgs = (req: {
|
|
7
7
|
format: "csv" | "json" | "parquet";
|
|
8
|
-
}) => Promise<string>;
|
|
8
|
+
}) => Promise<{ url: string; filename: string }>;
|
|
9
9
|
|
|
10
10
|
export const DownloadAsSchema = rpc
|
|
11
11
|
.input(
|
|
@@ -13,4 +13,9 @@ export const DownloadAsSchema = rpc
|
|
|
13
13
|
format: z.enum(["csv", "json", "parquet"]),
|
|
14
14
|
}),
|
|
15
15
|
)
|
|
16
|
-
.output(
|
|
16
|
+
.output(
|
|
17
|
+
z.object({
|
|
18
|
+
url: z.string(),
|
|
19
|
+
filename: z.string(),
|
|
20
|
+
}),
|
|
21
|
+
);
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { Fill } from "@marimo-team/react-slotz";
|
|
4
|
+
import type { OnChangeFn, RowSelectionState } from "@tanstack/react-table";
|
|
5
|
+
import type React from "react";
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { Tabs, TabsContent } from "@/components/ui/tabs";
|
|
8
|
+
import { SlotNames } from "@/core/slots/slots";
|
|
9
|
+
import type {
|
|
10
|
+
GetRowResult,
|
|
11
|
+
PreviewColumn,
|
|
12
|
+
} from "@/plugins/impl/DataTablePlugin";
|
|
13
|
+
import { cn } from "@/utils/cn";
|
|
14
|
+
import {
|
|
15
|
+
PANEL_TYPES,
|
|
16
|
+
type PanelType,
|
|
17
|
+
} from "../../editor/chrome/panels/context-aware-panel/context-aware-panel";
|
|
18
|
+
import { ColumnExplorerPanel } from "../column-explorer-panel/column-explorer";
|
|
19
|
+
import { RowViewerPanel } from "../row-viewer-panel/row-viewer";
|
|
20
|
+
import type { FieldTypesWithExternalType, TooManyRows } from "../types";
|
|
21
|
+
|
|
22
|
+
export interface TableExplorerPanelProps {
|
|
23
|
+
// Row viewer props
|
|
24
|
+
rowIdx: number;
|
|
25
|
+
setRowIdx: (rowIdx: number) => void;
|
|
26
|
+
totalRows: number | TooManyRows;
|
|
27
|
+
fieldTypes: FieldTypesWithExternalType | undefined | null;
|
|
28
|
+
getRow: (rowIdx: number) => Promise<GetRowResult>;
|
|
29
|
+
isSelectable: boolean;
|
|
30
|
+
isRowSelected: boolean;
|
|
31
|
+
handleRowSelectionChange?: OnChangeFn<RowSelectionState>;
|
|
32
|
+
// Column explorer props
|
|
33
|
+
previewColumn?: PreviewColumn;
|
|
34
|
+
totalColumns: number;
|
|
35
|
+
tableId: string;
|
|
36
|
+
// Visibility flags
|
|
37
|
+
showRowExplorer: boolean;
|
|
38
|
+
showColumnExplorer: boolean;
|
|
39
|
+
// Tab state (driven by contextAwarePanelType atom)
|
|
40
|
+
activeTab: PanelType | null;
|
|
41
|
+
onTabChange: (tab: PanelType) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const tabTriggerClassName =
|
|
45
|
+
"text-xs uppercase tracking-wide font-semibold cursor-pointer transition-colors";
|
|
46
|
+
const activeClassName = "text-primary";
|
|
47
|
+
const inactiveClassName = "hover:text-foreground";
|
|
48
|
+
|
|
49
|
+
export const TableExplorerPanel: React.FC<TableExplorerPanelProps> = ({
|
|
50
|
+
// Row viewer
|
|
51
|
+
rowIdx,
|
|
52
|
+
setRowIdx,
|
|
53
|
+
totalRows,
|
|
54
|
+
fieldTypes,
|
|
55
|
+
getRow,
|
|
56
|
+
isSelectable,
|
|
57
|
+
isRowSelected,
|
|
58
|
+
handleRowSelectionChange,
|
|
59
|
+
// Column explorer
|
|
60
|
+
previewColumn,
|
|
61
|
+
totalColumns,
|
|
62
|
+
tableId,
|
|
63
|
+
// Visibility
|
|
64
|
+
showRowExplorer,
|
|
65
|
+
showColumnExplorer,
|
|
66
|
+
// Tab state
|
|
67
|
+
activeTab,
|
|
68
|
+
onTabChange,
|
|
69
|
+
}) => {
|
|
70
|
+
const showTabs = showRowExplorer && showColumnExplorer;
|
|
71
|
+
|
|
72
|
+
const rowViewer = (
|
|
73
|
+
<RowViewerPanel
|
|
74
|
+
rowIdx={rowIdx}
|
|
75
|
+
setRowIdx={setRowIdx}
|
|
76
|
+
totalRows={totalRows}
|
|
77
|
+
fieldTypes={fieldTypes}
|
|
78
|
+
getRow={getRow}
|
|
79
|
+
isSelectable={isSelectable}
|
|
80
|
+
isRowSelected={isRowSelected}
|
|
81
|
+
handleRowSelectionChange={handleRowSelectionChange}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const columnExplorer = previewColumn && (
|
|
86
|
+
<ColumnExplorerPanel
|
|
87
|
+
previewColumn={previewColumn}
|
|
88
|
+
fieldTypes={fieldTypes}
|
|
89
|
+
totalRows={totalRows}
|
|
90
|
+
totalColumns={totalColumns}
|
|
91
|
+
tableId={tableId}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// If only one panel is visible, don't show tabs
|
|
96
|
+
if (!showTabs) {
|
|
97
|
+
if (showRowExplorer) {
|
|
98
|
+
return rowViewer;
|
|
99
|
+
}
|
|
100
|
+
if (showColumnExplorer) {
|
|
101
|
+
return columnExplorer;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Resolve active tab — fall back to first available
|
|
107
|
+
const resolvedTab = activeTab ?? PANEL_TYPES.ROW_VIEWER;
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<Tabs
|
|
111
|
+
value={resolvedTab}
|
|
112
|
+
onValueChange={(value) => onTabChange(value as PanelType)}
|
|
113
|
+
className="h-full flex flex-col min-w-[350px]"
|
|
114
|
+
>
|
|
115
|
+
<Fill name={SlotNames.CONTEXT_AWARE_PANEL_HEADER}>
|
|
116
|
+
<div className="flex items-center gap-1">
|
|
117
|
+
<Button
|
|
118
|
+
variant="text"
|
|
119
|
+
size="xs"
|
|
120
|
+
onClick={() => onTabChange(PANEL_TYPES.ROW_VIEWER)}
|
|
121
|
+
className={cn(
|
|
122
|
+
tabTriggerClassName,
|
|
123
|
+
resolvedTab === PANEL_TYPES.ROW_VIEWER
|
|
124
|
+
? activeClassName
|
|
125
|
+
: inactiveClassName,
|
|
126
|
+
)}
|
|
127
|
+
>
|
|
128
|
+
Rows
|
|
129
|
+
</Button>
|
|
130
|
+
<span className="text-muted-foreground text-xs">|</span>
|
|
131
|
+
<Button
|
|
132
|
+
variant="text"
|
|
133
|
+
size="xs"
|
|
134
|
+
onClick={() => onTabChange(PANEL_TYPES.COLUMN_EXPLORER)}
|
|
135
|
+
className={cn(
|
|
136
|
+
tabTriggerClassName,
|
|
137
|
+
resolvedTab === PANEL_TYPES.COLUMN_EXPLORER
|
|
138
|
+
? activeClassName
|
|
139
|
+
: inactiveClassName,
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
Explorer
|
|
143
|
+
</Button>
|
|
144
|
+
</div>
|
|
145
|
+
</Fill>
|
|
146
|
+
|
|
147
|
+
<TabsContent
|
|
148
|
+
value={PANEL_TYPES.ROW_VIEWER}
|
|
149
|
+
className="flex-1 overflow-auto"
|
|
150
|
+
>
|
|
151
|
+
{rowViewer}
|
|
152
|
+
</TabsContent>
|
|
153
|
+
<TabsContent
|
|
154
|
+
value={PANEL_TYPES.COLUMN_EXPLORER}
|
|
155
|
+
className="flex-1 overflow-auto"
|
|
156
|
+
>
|
|
157
|
+
{columnExplorer}
|
|
158
|
+
</TabsContent>
|
|
159
|
+
</Tabs>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
@@ -21,7 +21,12 @@ import {
|
|
|
21
21
|
isPinnedAtom,
|
|
22
22
|
} from "./atoms";
|
|
23
23
|
|
|
24
|
-
export
|
|
24
|
+
export const PANEL_TYPES = {
|
|
25
|
+
ROW_VIEWER: "row-viewer",
|
|
26
|
+
COLUMN_EXPLORER: "column-explorer",
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export type PanelType = (typeof PANEL_TYPES)[keyof typeof PANEL_TYPES];
|
|
25
30
|
|
|
26
31
|
export const ContextAwarePanel: React.FC = () => {
|
|
27
32
|
const [owner, setOwner] = useAtom(contextAwarePanelOwner);
|
|
@@ -51,7 +56,7 @@ export const ContextAwarePanel: React.FC = () => {
|
|
|
51
56
|
aria-label={isPinned ? "Unpin panel" : "Pin panel"}
|
|
52
57
|
>
|
|
53
58
|
{isPinned ? (
|
|
54
|
-
<PinIcon className="w-4 h-4" />
|
|
59
|
+
<PinIcon className="w-4 h-4 text-primary" />
|
|
55
60
|
) : (
|
|
56
61
|
<PinOffIcon className="w-4 h-4" />
|
|
57
62
|
)}
|
|
@@ -95,16 +100,18 @@ export const ContextAwarePanel: React.FC = () => {
|
|
|
95
100
|
|
|
96
101
|
const renderBody = () => {
|
|
97
102
|
return (
|
|
98
|
-
<div className="
|
|
99
|
-
<div className="
|
|
103
|
+
<div className="pb-7 mb-4 h-full overflow-auto">
|
|
104
|
+
<div className="p-3 border-b flex justify-between items-center">
|
|
100
105
|
{renderModeToggle()}
|
|
106
|
+
<Slot name={SlotNames.CONTEXT_AWARE_PANEL_HEADER} />
|
|
101
107
|
<Button
|
|
102
|
-
variant="
|
|
103
|
-
size="
|
|
108
|
+
variant="text"
|
|
109
|
+
size="xs"
|
|
110
|
+
className="m-0"
|
|
104
111
|
onClick={closePanel}
|
|
105
112
|
aria-label="Close selection panel"
|
|
106
113
|
>
|
|
107
|
-
<XIcon className="w-4 h-4" />
|
|
114
|
+
<XIcon className="w-4 h-4 hover:text-destructive" />
|
|
108
115
|
</Button>
|
|
109
116
|
</div>
|
|
110
117
|
|
|
@@ -126,7 +133,7 @@ export const ContextAwarePanel: React.FC = () => {
|
|
|
126
133
|
onDragging={handleDragging}
|
|
127
134
|
className="resize-handle border-border z-20 print:hidden border-l"
|
|
128
135
|
/>
|
|
129
|
-
<Panel defaultSize={
|
|
136
|
+
<Panel defaultSize={25} minSize={25} maxSize={80}>
|
|
130
137
|
{renderBody()}
|
|
131
138
|
</Panel>
|
|
132
139
|
</>
|
|
@@ -150,7 +157,7 @@ interface ResizableComponentProps {
|
|
|
150
157
|
const ResizableComponent = ({ children }: ResizableComponentProps) => {
|
|
151
158
|
const { resizableDivRef, handleRefs, style } = useResizeHandle({
|
|
152
159
|
startingWidth: 400,
|
|
153
|
-
minWidth:
|
|
160
|
+
minWidth: 400,
|
|
154
161
|
maxWidth: 1500,
|
|
155
162
|
onResize: () => {
|
|
156
163
|
raf2(() => {
|
package/src/core/slots/slots.ts
CHANGED
|
@@ -26,7 +26,6 @@ import type { CellSelectionState } from "@/components/data-table/cell-selection/
|
|
|
26
26
|
import type { CellStyleState } from "@/components/data-table/cell-styling/types";
|
|
27
27
|
import { TablePanel } from "@/components/data-table/charts/charts";
|
|
28
28
|
import { hasChart } from "@/components/data-table/charts/storage";
|
|
29
|
-
import { ColumnExplorerPanel } from "@/components/data-table/column-explorer-panel/column-explorer";
|
|
30
29
|
import { ColumnChartSpecModel } from "@/components/data-table/column-summary/chart-spec-model";
|
|
31
30
|
import { ColumnChartContext } from "@/components/data-table/column-summary/column-summary";
|
|
32
31
|
import {
|
|
@@ -35,11 +34,11 @@ import {
|
|
|
35
34
|
} from "@/components/data-table/filters";
|
|
36
35
|
import { usePanelOwnership } from "@/components/data-table/hooks/use-panel-ownership";
|
|
37
36
|
import { LoadingTable } from "@/components/data-table/loading-table";
|
|
38
|
-
import { RowViewerPanel } from "@/components/data-table/row-viewer-panel/row-viewer";
|
|
39
37
|
import {
|
|
40
38
|
type DownloadAsArgs,
|
|
41
39
|
DownloadAsSchema,
|
|
42
40
|
} from "@/components/data-table/schemas";
|
|
41
|
+
import { TableExplorerPanel } from "@/components/data-table/table-explorer-panel/table-explorer-panel";
|
|
43
42
|
import {
|
|
44
43
|
type BinValues,
|
|
45
44
|
type ColumnHeaderStats,
|
|
@@ -201,7 +200,6 @@ interface Data<T> {
|
|
|
201
200
|
hasStableRowId: boolean;
|
|
202
201
|
lazy: boolean;
|
|
203
202
|
cellHoverTexts?: Record<string, Record<string, string | null>> | null;
|
|
204
|
-
downloadFileName?: string;
|
|
205
203
|
}
|
|
206
204
|
|
|
207
205
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
@@ -287,7 +285,6 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
|
|
|
287
285
|
// If lazy, this will preload the first page of data
|
|
288
286
|
// without user confirmation.
|
|
289
287
|
preload: z.boolean().default(false),
|
|
290
|
-
downloadFileName: z.string().optional(),
|
|
291
288
|
}),
|
|
292
289
|
)
|
|
293
290
|
.withFunctions<DataTableFunctions>({
|
|
@@ -823,7 +820,6 @@ const DataTableComponent = ({
|
|
|
823
820
|
cellStyles,
|
|
824
821
|
hoverTemplate,
|
|
825
822
|
cellHoverTexts,
|
|
826
|
-
downloadFileName,
|
|
827
823
|
toggleDisplayHeader,
|
|
828
824
|
calculate_top_k_rows,
|
|
829
825
|
preview_column,
|
|
@@ -839,7 +835,8 @@ const DataTableComponent = ({
|
|
|
839
835
|
}): JSX.Element => {
|
|
840
836
|
const id = useId();
|
|
841
837
|
const [viewedRowIdx, setViewedRowIdx] = useState(0);
|
|
842
|
-
const { isPanelOpen, togglePanel } =
|
|
838
|
+
const { isPanelOpen, isAnyPanelOpen, togglePanel, panelType, setPanelType } =
|
|
839
|
+
usePanelOwnership(id, cellId);
|
|
843
840
|
|
|
844
841
|
const chartSpecModel = useMemo(() => {
|
|
845
842
|
if (!columnSummaries) {
|
|
@@ -1002,8 +999,7 @@ const DataTableComponent = ({
|
|
|
1002
999
|
);
|
|
1003
1000
|
|
|
1004
1001
|
const isSelectable = selection === "multi" || selection === "single";
|
|
1005
|
-
const
|
|
1006
|
-
showColumnExplorer && preview_column && isPanelOpen("column-explorer");
|
|
1002
|
+
const canShowColumnExplorer = showColumnExplorer && !!preview_column;
|
|
1007
1003
|
|
|
1008
1004
|
const isInVscode = isInVscodeExtension();
|
|
1009
1005
|
|
|
@@ -1032,28 +1028,24 @@ const DataTableComponent = ({
|
|
|
1032
1028
|
</Banner>
|
|
1033
1029
|
)}
|
|
1034
1030
|
|
|
1035
|
-
{
|
|
1031
|
+
{isAnyPanelOpen && (showRowExplorer || canShowColumnExplorer) && (
|
|
1036
1032
|
<ContextAwarePanelItem>
|
|
1037
|
-
<
|
|
1038
|
-
getRow={getRow}
|
|
1039
|
-
fieldTypes={memoizedUnclampedFieldTypes}
|
|
1040
|
-
totalRows={totalRows}
|
|
1033
|
+
<TableExplorerPanel
|
|
1041
1034
|
rowIdx={viewedRowIdx}
|
|
1042
1035
|
setRowIdx={setViewedRow}
|
|
1036
|
+
totalRows={totalRows}
|
|
1037
|
+
fieldTypes={memoizedUnclampedFieldTypes}
|
|
1038
|
+
getRow={getRow}
|
|
1043
1039
|
isSelectable={isSelectable}
|
|
1044
|
-
isRowSelected={rowSelection[viewedRowIdx]}
|
|
1040
|
+
isRowSelected={Boolean(rowSelection[viewedRowIdx])}
|
|
1045
1041
|
handleRowSelectionChange={handleRowSelectionChange}
|
|
1046
|
-
/>
|
|
1047
|
-
</ContextAwarePanelItem>
|
|
1048
|
-
)}
|
|
1049
|
-
{showColExplorer && (
|
|
1050
|
-
<ContextAwarePanelItem>
|
|
1051
|
-
<ColumnExplorerPanel
|
|
1052
1042
|
previewColumn={preview_column}
|
|
1053
|
-
fieldTypes={memoizedUnclampedFieldTypes}
|
|
1054
|
-
totalRows={totalRows}
|
|
1055
1043
|
totalColumns={totalColumns}
|
|
1056
1044
|
tableId={id}
|
|
1045
|
+
showRowExplorer={showRowExplorer && !isInVscode}
|
|
1046
|
+
showColumnExplorer={canShowColumnExplorer && !isInVscode}
|
|
1047
|
+
activeTab={panelType}
|
|
1048
|
+
onTabChange={setPanelType}
|
|
1057
1049
|
/>
|
|
1058
1050
|
</ContextAwarePanelItem>
|
|
1059
1051
|
)}
|
|
@@ -1082,7 +1074,6 @@ const DataTableComponent = ({
|
|
|
1082
1074
|
hoverTemplate={hoverTemplate}
|
|
1083
1075
|
cellHoverTexts={cellHoverTexts}
|
|
1084
1076
|
downloadAs={showDownload ? downloadAs : undefined}
|
|
1085
|
-
downloadFileName={downloadFileName}
|
|
1086
1077
|
enableSearch={enableSearch}
|
|
1087
1078
|
searchQuery={searchQuery}
|
|
1088
1079
|
onSearchQueryChange={setSearchQuery}
|
|
@@ -1099,11 +1090,13 @@ const DataTableComponent = ({
|
|
|
1099
1090
|
showChartBuilder={showChartBuilder}
|
|
1100
1091
|
showPageSizeSelector={showPageSizeSelector}
|
|
1101
1092
|
// Hidden in VSCode (for now) because we don't have a panel to show
|
|
1102
|
-
// the
|
|
1103
|
-
|
|
1104
|
-
|
|
1093
|
+
// the table explorer.
|
|
1094
|
+
showTableExplorer={
|
|
1095
|
+
(showRowExplorer || canShowColumnExplorer) && !isInVscode
|
|
1096
|
+
}
|
|
1105
1097
|
togglePanel={togglePanel}
|
|
1106
1098
|
isPanelOpen={isPanelOpen}
|
|
1099
|
+
isAnyPanelOpen={isAnyPanelOpen}
|
|
1107
1100
|
viewedRowIdx={viewedRowIdx}
|
|
1108
1101
|
onViewedRowChange={(rowIdx) => setViewedRowIdx(rowIdx)}
|
|
1109
1102
|
/>
|
|
@@ -329,7 +329,6 @@ export const DataFrameComponent = memo(
|
|
|
329
329
|
fieldTypes={field_types}
|
|
330
330
|
rowHeaders={row_headers || Arrays.EMPTY}
|
|
331
331
|
showDownload={showDownload}
|
|
332
|
-
downloadFileName={dataframeName}
|
|
333
332
|
download_as={download_as}
|
|
334
333
|
enableSearch={false}
|
|
335
334
|
showFilters={false}
|