@marimo-team/islands 0.23.7-dev5 → 0.23.7-dev7
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/{code-visibility-D8E8Ctez.js → code-visibility-CiN3Xnfo.js} +591 -580
- package/dist/main.js +900 -891
- package/dist/{reveal-component-Ycn2n8kH.js → reveal-component-BCKa3sr-.js} +1 -1
- package/package.json +1 -1
- package/src/components/data-table/TableTopBar.tsx +5 -1
- package/src/components/data-table/data-table.tsx +5 -0
- package/src/components/data-table/download-policy/atoms.ts +10 -0
- package/src/components/data-table/export-actions.tsx +31 -4
- package/src/plugins/impl/DataTablePlugin.tsx +12 -0
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +6 -0
|
@@ -8,7 +8,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
9
|
import "./html-to-image-hMMPiNe_.js";
|
|
10
10
|
import "./chunk-5FQGJX7Z-CO1e63h_.js";
|
|
11
|
-
import { Ft as Code, Mt as Expand, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as EyeOff, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-
|
|
11
|
+
import { Ft as Code, Mt as Expand, a as DEFAULT_SLIDE_TYPE, c as Slide, i as DEFAULT_DECK_TRANSITION, jt as EyeOff, s as SlideSidebar, t as useNotebookCodeAvailable } from "./code-visibility-CiN3Xnfo.js";
|
|
12
12
|
import "./input-BAOe64zx.js";
|
|
13
13
|
import "./toDate-CHtl9vts.js";
|
|
14
14
|
import "./react-dom-BWRJ_g_k.js";
|
package/package.json
CHANGED
|
@@ -34,6 +34,7 @@ interface TableTopBarProps extends Partial<ExportActionProps> {
|
|
|
34
34
|
showTableExplorer?: boolean;
|
|
35
35
|
togglePanel?: (panelType: PanelType) => void;
|
|
36
36
|
isAnyPanelOpen?: boolean;
|
|
37
|
+
sizeBytes?: number | null;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export const TableTopBar: React.FC<TableTopBarProps> = ({
|
|
@@ -48,6 +49,7 @@ export const TableTopBar: React.FC<TableTopBarProps> = ({
|
|
|
48
49
|
togglePanel,
|
|
49
50
|
isAnyPanelOpen,
|
|
50
51
|
downloadAs,
|
|
52
|
+
sizeBytes,
|
|
51
53
|
}) => {
|
|
52
54
|
const [internalValue, setInternalValue] = useState(searchQuery || "");
|
|
53
55
|
const debouncedSearch = useDebounce(internalValue, 500);
|
|
@@ -130,7 +132,9 @@ export const TableTopBar: React.FC<TableTopBarProps> = ({
|
|
|
130
132
|
Explore
|
|
131
133
|
</Button>
|
|
132
134
|
)}
|
|
133
|
-
{downloadAs &&
|
|
135
|
+
{downloadAs && (
|
|
136
|
+
<ExportMenu downloadAs={downloadAs} sizeBytes={sizeBytes} />
|
|
137
|
+
)}
|
|
134
138
|
</div>
|
|
135
139
|
</div>
|
|
136
140
|
);
|
|
@@ -70,6 +70,9 @@ interface DataTableProps<TData> extends Partial<ExportActionProps> {
|
|
|
70
70
|
setSorting?: OnChangeFn<SortingState>; // controlled sorting
|
|
71
71
|
// Pagination
|
|
72
72
|
totalRows: number | TooManyRows;
|
|
73
|
+
// JSON-serialized size of the currently-rendered data. Forwarded to
|
|
74
|
+
// ExportMenu so hosts can size-gate the Export button via downloadSizeLimitAtom.
|
|
75
|
+
sizeBytes?: number | null;
|
|
73
76
|
totalColumns: number;
|
|
74
77
|
pagination?: boolean;
|
|
75
78
|
manualPagination?: boolean; // server-side pagination
|
|
@@ -121,6 +124,7 @@ const DataTableInternal = <TData,>({
|
|
|
121
124
|
selection,
|
|
122
125
|
totalColumns,
|
|
123
126
|
totalRows,
|
|
127
|
+
sizeBytes,
|
|
124
128
|
manualSorting = false,
|
|
125
129
|
sorting,
|
|
126
130
|
setSorting,
|
|
@@ -309,6 +313,7 @@ const DataTableInternal = <TData,>({
|
|
|
309
313
|
togglePanel={togglePanel}
|
|
310
314
|
isAnyPanelOpen={isAnyPanelOpen}
|
|
311
315
|
downloadAs={downloadAs}
|
|
316
|
+
sizeBytes={sizeBytes}
|
|
312
317
|
/>
|
|
313
318
|
<Table
|
|
314
319
|
className={cn(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
3
4
|
import {
|
|
4
5
|
BracesIcon,
|
|
5
6
|
BrickWallIcon,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
} from "lucide-react";
|
|
10
11
|
import React from "react";
|
|
11
12
|
import { useLocale } from "react-aria";
|
|
13
|
+
import { downloadSizeLimitAtom } from "./download-policy/atoms";
|
|
12
14
|
import { logNever } from "@/utils/assertNever";
|
|
13
15
|
import { cn } from "@/utils/cn";
|
|
14
16
|
import { copyToClipboard } from "@/utils/copy";
|
|
@@ -84,6 +86,11 @@ export interface ExportActionProps {
|
|
|
84
86
|
error?: string | null;
|
|
85
87
|
missing_packages?: string[] | null;
|
|
86
88
|
}>;
|
|
89
|
+
// JSON-serialized size of the currently-rendered data. Used together with
|
|
90
|
+
// downloadSizeLimitAtom to disable the Export button when a host (e.g.,
|
|
91
|
+
// marimo-lsp inside VS Code) declares a download size cap. Null/undefined
|
|
92
|
+
// means "no info" and the gate stays disabled (fail-open).
|
|
93
|
+
sizeBytes?: number | null;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
const labelForDownloadFormat = (format: DownloadFormat): string =>
|
|
@@ -94,12 +101,19 @@ const labelForCopyFormat = (format: CopyFormat): string =>
|
|
|
94
101
|
export const ExportMenu: React.FC<ExportActionProps> = (props) => {
|
|
95
102
|
const { locale } = useLocale();
|
|
96
103
|
const [open, setOpen] = React.useState(false);
|
|
104
|
+
const policy = useAtomValue(downloadSizeLimitAtom);
|
|
105
|
+
const disabled = !!(
|
|
106
|
+
policy &&
|
|
107
|
+
props.sizeBytes != null &&
|
|
108
|
+
props.sizeBytes > policy.limitBytes
|
|
109
|
+
);
|
|
97
110
|
|
|
98
111
|
const button = (
|
|
99
112
|
<Button
|
|
100
113
|
data-testid="export-button"
|
|
101
114
|
size="xs"
|
|
102
115
|
variant="text"
|
|
116
|
+
disabled={disabled}
|
|
103
117
|
className={cn(
|
|
104
118
|
"print:hidden text-xs gap-1",
|
|
105
119
|
open ? "text-primary" : "text-muted-foreground",
|
|
@@ -113,7 +127,10 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
|
|
|
113
127
|
const resolveDownloadUrl = async (
|
|
114
128
|
format: DownloadFormat,
|
|
115
129
|
onRetry: () => void,
|
|
116
|
-
): Promise<{
|
|
130
|
+
): Promise<{
|
|
131
|
+
url: string;
|
|
132
|
+
filename: string;
|
|
133
|
+
} | null> => {
|
|
117
134
|
let response: Awaited<ReturnType<typeof props.downloadAs>>;
|
|
118
135
|
try {
|
|
119
136
|
response = await props.downloadAs({ format });
|
|
@@ -143,7 +160,10 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
|
|
|
143
160
|
return null;
|
|
144
161
|
}
|
|
145
162
|
|
|
146
|
-
return {
|
|
163
|
+
return {
|
|
164
|
+
url: response.url,
|
|
165
|
+
filename: response.filename,
|
|
166
|
+
};
|
|
147
167
|
};
|
|
148
168
|
|
|
149
169
|
const handleDownload = async (format: DownloadFormat) => {
|
|
@@ -229,8 +249,15 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
|
|
|
229
249
|
|
|
230
250
|
return (
|
|
231
251
|
<DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
|
|
232
|
-
<Tooltip
|
|
233
|
-
|
|
252
|
+
<Tooltip
|
|
253
|
+
content={disabled ? policy?.unavailableMessage : "Export"}
|
|
254
|
+
open={open ? false : undefined}
|
|
255
|
+
>
|
|
256
|
+
<DropdownMenuTrigger asChild={true} disabled={disabled}>
|
|
257
|
+
<span tabIndex={disabled ? 0 : -1} className="inline-flex">
|
|
258
|
+
{button}
|
|
259
|
+
</span>
|
|
260
|
+
</DropdownMenuTrigger>
|
|
234
261
|
</Tooltip>
|
|
235
262
|
<DropdownMenuContent side="bottom" className="print:hidden">
|
|
236
263
|
<DropdownMenuLabel className="text-xs text-muted-foreground">
|
|
@@ -194,6 +194,7 @@ interface Data<T> {
|
|
|
194
194
|
wrappedColumns?: string[];
|
|
195
195
|
headerTooltip?: Record<string, string>;
|
|
196
196
|
totalColumns: number;
|
|
197
|
+
sizeBytes?: number | null;
|
|
197
198
|
maxColumns: number | "all";
|
|
198
199
|
hasStableRowId: boolean;
|
|
199
200
|
lazy: boolean;
|
|
@@ -220,6 +221,7 @@ type DataTableFunctions = {
|
|
|
220
221
|
cell_styles?: CellStyleState | null;
|
|
221
222
|
cell_hover_texts?: Record<string, Record<string, string | null>> | null;
|
|
222
223
|
raw_data?: TableData<T> | null;
|
|
224
|
+
size_bytes?: number | null;
|
|
223
225
|
}>;
|
|
224
226
|
get_data_url?: GetDataUrl;
|
|
225
227
|
get_row_ids?: GetRowIds;
|
|
@@ -270,6 +272,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
|
|
|
270
272
|
headerTooltip: z.record(z.string(), z.string()).optional(),
|
|
271
273
|
fieldTypes: columnToFieldTypesSchema.nullish(),
|
|
272
274
|
totalColumns: z.number(),
|
|
275
|
+
sizeBytes: z.number().nullish(),
|
|
273
276
|
maxColumns: z.union([z.number(), z.literal("all")]).default("all"),
|
|
274
277
|
hasStableRowId: z.boolean().default(false),
|
|
275
278
|
maxHeight: z.number().optional(),
|
|
@@ -327,6 +330,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
|
|
|
327
330
|
.nullable(),
|
|
328
331
|
cell_hover_texts: cellHoverTextSchema.nullable(),
|
|
329
332
|
raw_data: z.union([z.string(), z.array(z.looseObject({}))]).nullish(),
|
|
333
|
+
size_bytes: z.number().nullish(),
|
|
330
334
|
}),
|
|
331
335
|
),
|
|
332
336
|
get_row_ids: rpc.input(z.object({}).passthrough()).output(
|
|
@@ -532,6 +536,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
532
536
|
rows: T[];
|
|
533
537
|
rawRows?: T[];
|
|
534
538
|
totalRows: number | TooManyRows;
|
|
539
|
+
sizeBytes?: number | null;
|
|
535
540
|
cellStyles: CellStyleState | undefined | null;
|
|
536
541
|
cellHoverTexts?: Record<string, Record<string, string | null>> | null;
|
|
537
542
|
}>(async () => {
|
|
@@ -548,6 +553,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
548
553
|
let tableData = props.data;
|
|
549
554
|
let rawTableData: TableData<T> | undefined | null = props.rawData;
|
|
550
555
|
let totalRows = props.totalRows;
|
|
556
|
+
let sizeBytes = props.sizeBytes ?? null;
|
|
551
557
|
let cellStyles = props.cellStyles;
|
|
552
558
|
let cellHoverTexts = props.cellHoverTexts;
|
|
553
559
|
|
|
@@ -591,6 +597,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
591
597
|
tableData = searchResults.data;
|
|
592
598
|
rawTableData = searchResults.raw_data;
|
|
593
599
|
totalRows = searchResults.total_rows;
|
|
600
|
+
sizeBytes = searchResults.size_bytes ?? null;
|
|
594
601
|
cellStyles = searchResults.cell_styles || {};
|
|
595
602
|
cellHoverTexts = searchResults.cell_hover_texts || {};
|
|
596
603
|
}
|
|
@@ -603,6 +610,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
603
610
|
rows: tableData,
|
|
604
611
|
rawRows: rawData,
|
|
605
612
|
totalRows: totalRows,
|
|
613
|
+
sizeBytes,
|
|
606
614
|
cellStyles,
|
|
607
615
|
cellHoverTexts,
|
|
608
616
|
};
|
|
@@ -614,6 +622,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
614
622
|
useDeepCompareMemoize(props.fieldTypes),
|
|
615
623
|
props.data,
|
|
616
624
|
props.totalRows,
|
|
625
|
+
props.sizeBytes,
|
|
617
626
|
props.lazy,
|
|
618
627
|
props.cellHoverTexts,
|
|
619
628
|
props.cellStyles,
|
|
@@ -728,6 +737,7 @@ export const LoadingDataTableComponent = memo(
|
|
|
728
737
|
setFilters={setFilters}
|
|
729
738
|
reloading={isFetching && !isPending}
|
|
730
739
|
totalRows={data?.totalRows ?? props.totalRows}
|
|
740
|
+
sizeBytes={data?.sizeBytes ?? props.sizeBytes ?? null}
|
|
731
741
|
paginationState={paginationState}
|
|
732
742
|
setPaginationState={setPaginationState}
|
|
733
743
|
cellStyles={data?.cellStyles ?? props.cellStyles}
|
|
@@ -774,6 +784,7 @@ const DataTableComponent = ({
|
|
|
774
784
|
data,
|
|
775
785
|
rawData,
|
|
776
786
|
totalRows,
|
|
787
|
+
sizeBytes,
|
|
777
788
|
maxColumns,
|
|
778
789
|
pagination,
|
|
779
790
|
selection,
|
|
@@ -1053,6 +1064,7 @@ const DataTableComponent = ({
|
|
|
1053
1064
|
maxHeight={maxHeight}
|
|
1054
1065
|
sorting={sorting}
|
|
1055
1066
|
totalRows={totalRows}
|
|
1067
|
+
sizeBytes={sizeBytes}
|
|
1056
1068
|
totalColumns={totalColumns}
|
|
1057
1069
|
manualSorting={true}
|
|
1058
1070
|
setSorting={setSorting}
|
|
@@ -64,6 +64,7 @@ type PluginFunctions = {
|
|
|
64
64
|
column_types_per_step: FieldTypesWithExternalType[];
|
|
65
65
|
python_code?: string | null;
|
|
66
66
|
sql_code?: string | null;
|
|
67
|
+
size_bytes?: number | null;
|
|
67
68
|
}>;
|
|
68
69
|
get_column_values: (req: { column: string }) => Promise<{
|
|
69
70
|
values: unknown[];
|
|
@@ -81,6 +82,7 @@ type PluginFunctions = {
|
|
|
81
82
|
}) => Promise<{
|
|
82
83
|
data: TableData<T>;
|
|
83
84
|
total_rows: number;
|
|
85
|
+
size_bytes?: number | null;
|
|
84
86
|
}>;
|
|
85
87
|
download_as: DownloadAsArgs;
|
|
86
88
|
};
|
|
@@ -118,6 +120,7 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
|
|
|
118
120
|
column_types_per_step: z.array(columnToFieldTypesSchema),
|
|
119
121
|
python_code: z.string().nullish(),
|
|
120
122
|
sql_code: z.string().nullish(),
|
|
123
|
+
size_bytes: z.number().nullish(),
|
|
121
124
|
}),
|
|
122
125
|
),
|
|
123
126
|
get_column_values: rpc.input(z.object({ column: z.string() })).output(
|
|
@@ -147,6 +150,7 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
|
|
|
147
150
|
z.object({
|
|
148
151
|
data: z.union([z.string(), z.array(z.object({}).passthrough())]),
|
|
149
152
|
total_rows: z.number(),
|
|
153
|
+
size_bytes: z.number().nullish(),
|
|
150
154
|
}),
|
|
151
155
|
),
|
|
152
156
|
download_as: DownloadAsSchema,
|
|
@@ -203,6 +207,7 @@ export const DataFrameComponent = memo(
|
|
|
203
207
|
column_types_per_step,
|
|
204
208
|
python_code,
|
|
205
209
|
sql_code,
|
|
210
|
+
size_bytes,
|
|
206
211
|
} = data || {};
|
|
207
212
|
|
|
208
213
|
const totalColumns = field_types?.length;
|
|
@@ -322,6 +327,7 @@ export const DataFrameComponent = memo(
|
|
|
322
327
|
data={url || ""}
|
|
323
328
|
hasStableRowId={false}
|
|
324
329
|
totalRows={total_rows ?? 0}
|
|
330
|
+
sizeBytes={size_bytes ?? null}
|
|
325
331
|
totalColumns={totalColumns ?? 0}
|
|
326
332
|
maxColumns="all"
|
|
327
333
|
pageSize={pageSize}
|