@marimo-team/islands 0.23.12-dev2 → 0.23.12-dev20
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/{ConnectedDataExplorerComponent-WqG-xX4l.js → ConnectedDataExplorerComponent-Du3_nUzI.js} +13 -13
- package/dist/{ErrorBoundary-BNx_OSVo.js → ErrorBoundary-DE6tzZf-.js} +2 -2
- package/dist/{any-language-editor-rPSlOll9.js → any-language-editor-DN1R-1KZ.js} +5 -5
- package/dist/{button-vQhauTmO.js → button-BacYv-bE.js} +7 -1
- package/dist/{capabilities-BEHzIS99.js → capabilities-D_4LYhSU.js} +1 -1
- package/dist/{chat-ui-k2kqhCv5.js → chat-ui-CsPewo4h.js} +16 -16
- package/dist/{check-nrzHDi45.js → check-C9OoNtR4.js} +1 -1
- package/dist/{code-visibility-DZ_6U5hT.js → code-visibility-02AuLxDs.js} +664 -663
- package/dist/{copy-UhDed7D4.js → copy-COam1EG7.js} +2 -2
- package/dist/{dist-DYGLrbYQ.js → dist--2Bqjvs0.js} +2 -2
- package/dist/{error-banner-BHAkVFc2.js → error-banner-DFPfz_Qf.js} +2 -2
- package/dist/{esm-Bqu9AE2K.js → esm-M837UxV5.js} +1 -1
- package/dist/{extends-9Yl5BEcg.js → extends-9MVIxxRo.js} +4 -4
- package/dist/{formats-BV4bOfMI.js → formats-d6MhLuQ9.js} +4 -4
- package/dist/{glide-data-editor-BDTq6YUb.js → glide-data-editor-DkzAInWG.js} +9 -9
- package/dist/{html-to-image-C86pQALH.js → html-to-image-DXwLcQ6l.js} +95 -88
- package/dist/{input-AKkGXdyV.js → input-CbEz_aj_.js} +6 -6
- package/dist/{label-E3ZJXHu8.js → label-WfTSU8L4.js} +2 -2
- package/dist/{loader-YPuQvn1Y.js → loader-Boph2xIS.js} +1 -1
- package/dist/main.js +1753 -1626
- package/dist/{mermaid-QFAR9YgY.js → mermaid-CJW9vIyO.js} +5 -5
- package/dist/{process-output-nNw4OpSj.js → process-output-C6_e1pT_.js} +3 -3
- package/dist/{reveal-component-BxDb5eK0.js → reveal-component-CX0nM3qj.js} +11 -11
- package/dist/{spec-B45_YCNI.js → spec-Bv-XlYiv.js} +4 -4
- package/dist/{strings-Cq2s9_EQ.js → strings-Dq_j3Rxw.js} +4 -4
- package/dist/style.css +2 -2
- package/dist/{swiper-component-BNa_4kh2.js → swiper-component-5HoSsPi1.js} +2 -2
- package/dist/{toDate-Do1xRzAo.js → toDate-D-l5s8nn.js} +3 -3
- package/dist/{tooltip-Bz3OAwrU.js → tooltip-Czds6Qr8.js} +3 -3
- package/dist/{types-D8gEGs4R.js → types-C2Ir191_.js} +1 -1
- package/dist/{useAsyncData-CL3o2p4i.js → useAsyncData-1Dhzjfwf.js} +1 -1
- package/dist/{useDateFormatter-BC6iSz9g.js → useDateFormatter-CMnRuVmN.js} +2 -2
- package/dist/{useDeepCompareMemoize-BPx2MuOK.js → useDeepCompareMemoize-CDWT3BDz.js} +1 -1
- package/dist/{useIframeCapabilities-C6Ta3EyP.js → useIframeCapabilities-DWIYvDh7.js} +1 -1
- package/dist/{useLifecycle-C3Ec71q0.js → useLifecycle-AHlswLw-.js} +3 -3
- package/dist/{useTheme-ZhT6uIu3.js → useTheme-BrYvK-_A.js} +2 -2
- package/dist/{vega-component-C3AWYGAL.js → vega-component-Pk6lyc_a.js} +10 -10
- package/dist/{zod-DXqkaI_w.js → zod-CijjQh4u.js} +1 -1
- package/package.json +3 -3
- package/src/components/ai/display-helpers.tsx +5 -5
- package/src/components/app-config/ai-config.tsx +5 -5
- package/src/components/app-config/mcp-config.tsx +3 -3
- package/src/components/chat/acp/agent-panel.tsx +3 -3
- package/src/components/chat/acp/blocks.tsx +36 -38
- package/src/components/chat/acp/common.tsx +12 -16
- package/src/components/chat/acp/scroll-to-bottom-button.tsx +1 -1
- package/src/components/chat/acp/session-tabs.tsx +2 -2
- package/src/components/chat/chat-history-popover.tsx +1 -1
- package/src/components/chat/chat-panel.tsx +47 -23
- package/src/components/data-table/TableBottomBar.tsx +4 -1
- package/src/components/data-table/columns.tsx +2 -2
- package/src/components/data-table/data-table.tsx +26 -17
- package/src/components/data-table/filter-pill-editor.tsx +1 -1
- package/src/components/dependency-graph/minimap-content.tsx +1 -1
- package/src/components/editor/RecoveryButton.tsx +1 -1
- package/src/components/editor/actions/pair-with-agent-modal.tsx +2 -2
- package/src/components/editor/actions/useNotebookActions.tsx +4 -4
- package/src/components/editor/ai/__tests__/completion-utils.test.ts +91 -1
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -1
- package/src/components/editor/ai/completion-utils.ts +86 -1
- package/src/components/editor/cell/CreateCellButton.tsx +1 -1
- package/src/components/editor/chrome/panels/empty-state.tsx +1 -1
- package/src/components/editor/chrome/panels/outline/floating-outline.tsx +1 -1
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +1 -1
- package/src/components/editor/columns/cell-column.tsx +1 -1
- package/src/components/editor/columns/sortable-column.tsx +2 -2
- package/src/components/editor/output/MarimoErrorOutput.tsx +1 -1
- package/src/components/editor/output/TextOutput.tsx +2 -2
- package/src/components/home/components.tsx +4 -4
- package/src/components/icons/github.tsx +21 -0
- package/src/components/icons/youtube.tsx +21 -0
- package/src/components/slides/minimap.tsx +2 -2
- package/src/components/slides/reveal-component.tsx +1 -1
- package/src/components/storage/components.tsx +3 -7
- package/src/components/ui/alert.tsx +1 -1
- package/src/components/ui/command.tsx +2 -2
- package/src/components/ui/reorderable-list.tsx +1 -1
- package/src/components/ui/table.tsx +2 -5
- package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +67 -0
- package/src/core/codemirror/go-to-definition/__tests__/utils.test.ts +47 -0
- package/src/core/codemirror/go-to-definition/commands.ts +47 -30
- package/src/core/codemirror/go-to-definition/utils.ts +0 -1
- package/src/core/codemirror/language/languages/sql/renderers.tsx +60 -68
- package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +54 -0
- package/src/core/codemirror/reactive-references/analyzer.ts +44 -35
- package/src/core/hotkeys/hotkeys.ts +1 -0
- package/src/core/islands/__tests__/bridge.test.ts +25 -0
- package/src/core/islands/__tests__/parse.test.ts +585 -1
- package/src/core/islands/__tests__/test-utils.tsx +10 -1
- package/src/core/islands/bridge.ts +6 -1
- package/src/core/islands/constants.ts +2 -0
- package/src/core/islands/parse.ts +293 -13
- package/src/plugins/impl/DataTablePlugin.tsx +20 -1
- package/src/plugins/impl/FileBrowserPlugin.tsx +165 -74
- package/src/plugins/impl/MatrixPlugin.tsx +2 -2
- package/src/plugins/impl/TabsPlugin.tsx +1 -1
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +141 -1
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +314 -0
- package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +4 -1
- package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +34 -0
- package/src/plugins/impl/anywidget/__tests__/model.test.ts +19 -0
- package/src/plugins/impl/anywidget/model.ts +15 -0
- package/src/plugins/impl/matplotlib/matplotlib-renderer.ts +1 -1
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +155 -98
- package/src/plugins/impl/mpl-interactive/__tests__/MplInteractivePlugin.test.tsx +154 -1
- package/src/plugins/impl/mpl-interactive/mpl-websocket-shim.ts +10 -0
|
@@ -34,22 +34,22 @@ const PREVIEW_ITEM_LIMIT = 5;
|
|
|
34
34
|
|
|
35
35
|
// Color mappings for data types (Tailwind-safe)
|
|
36
36
|
const DATA_TYPE_COLORS: Record<DataType, string> = {
|
|
37
|
-
boolean: "bg-
|
|
38
|
-
date: "bg-
|
|
39
|
-
time: "bg-
|
|
40
|
-
datetime: "bg-
|
|
41
|
-
number: "bg-
|
|
42
|
-
integer: "bg-
|
|
43
|
-
string: "bg-
|
|
44
|
-
unknown: "bg-
|
|
37
|
+
boolean: "bg-(--orange-4) text-(--orange-11)",
|
|
38
|
+
date: "bg-(--grass-4) text-(--grass-11)",
|
|
39
|
+
time: "bg-(--grass-4) text-(--grass-11)",
|
|
40
|
+
datetime: "bg-(--grass-4) text-(--grass-11)",
|
|
41
|
+
number: "bg-(--purple-4) text-(--purple-11)",
|
|
42
|
+
integer: "bg-(--purple-4) text-(--purple-11)",
|
|
43
|
+
string: "bg-(--blue-4) text-(--blue-11)",
|
|
44
|
+
unknown: "bg-(--slate-4) text-(--slate-11)",
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
// Source type colors
|
|
48
48
|
const SOURCE_TYPE_COLORS = {
|
|
49
|
-
local: "bg-
|
|
50
|
-
duckdb: "bg-
|
|
51
|
-
connection: "bg-
|
|
52
|
-
catalog: "bg-
|
|
49
|
+
local: "bg-(--blue-4) text-(--blue-11)",
|
|
50
|
+
duckdb: "bg-(--amber-4) text-(--amber-11)",
|
|
51
|
+
connection: "bg-(--green-4) text-(--green-11)",
|
|
52
|
+
catalog: "bg-(--purple-4) text-(--purple-11)",
|
|
53
53
|
} as const;
|
|
54
54
|
|
|
55
55
|
const CONTAINER_STYLES = "p-3 min-w-[250px] flex flex-col divide-y";
|
|
@@ -78,7 +78,7 @@ const MetadataRow: React.FC<{
|
|
|
78
78
|
value: React.ReactNode;
|
|
79
79
|
}> = ({ label, value }) => (
|
|
80
80
|
<div className="flex items-center justify-between text-xs">
|
|
81
|
-
<span className="text-
|
|
81
|
+
<span className="text-(--slate-11)">{label}:</span>
|
|
82
82
|
{value}
|
|
83
83
|
</div>
|
|
84
84
|
);
|
|
@@ -89,7 +89,7 @@ const StatisticItem: React.FC<{
|
|
|
89
89
|
}> = ({ icon, text }) => (
|
|
90
90
|
<div className="flex items-center gap-1">
|
|
91
91
|
{icon}
|
|
92
|
-
<span className="text-xs text-
|
|
92
|
+
<span className="text-xs text-(--slate-11)">{text}</span>
|
|
93
93
|
</div>
|
|
94
94
|
);
|
|
95
95
|
|
|
@@ -109,14 +109,12 @@ const PreviewList: React.FC<{
|
|
|
109
109
|
return (
|
|
110
110
|
<div className="py-2">
|
|
111
111
|
{title && (
|
|
112
|
-
<h4 className="text-xs font-medium text-
|
|
113
|
-
{title}:
|
|
114
|
-
</h4>
|
|
112
|
+
<h4 className="text-xs font-medium text-(--slate-11) mb-2">{title}:</h4>
|
|
115
113
|
)}
|
|
116
114
|
<div className="flex flex-col gap-1 overflow-y-auto">
|
|
117
115
|
{visibleItems}
|
|
118
116
|
{hasMore && (
|
|
119
|
-
<div className="text-xs text-
|
|
117
|
+
<div className="text-xs text-(--slate-10) text-center py-1">
|
|
120
118
|
... and {totalCount - limit} more
|
|
121
119
|
</div>
|
|
122
120
|
)}
|
|
@@ -132,9 +130,9 @@ const getDataTypeColorClass = (dataType: DataType): string => {
|
|
|
132
130
|
export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
133
131
|
const tableIcon =
|
|
134
132
|
table.type === "view" ? (
|
|
135
|
-
<ViewIcon className="w-4 h-4 text-
|
|
133
|
+
<ViewIcon className="w-4 h-4 text-(--blue-9)" />
|
|
136
134
|
) : (
|
|
137
|
-
<TableIcon className="w-4 h-4 text-
|
|
135
|
+
<TableIcon className="w-4 h-4 text-(--green-9)" />
|
|
138
136
|
);
|
|
139
137
|
|
|
140
138
|
const typeBadge = (
|
|
@@ -142,8 +140,8 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
142
140
|
variant="secondary"
|
|
143
141
|
className={`text-xs ${
|
|
144
142
|
table.type === "view"
|
|
145
|
-
? "bg-
|
|
146
|
-
: "bg-
|
|
143
|
+
? "bg-(--blue-4) text-(--blue-11)"
|
|
144
|
+
: "bg-(--green-4) text-(--green-11)"
|
|
147
145
|
}`}
|
|
148
146
|
>
|
|
149
147
|
{table.type}
|
|
@@ -158,7 +156,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
158
156
|
className="flex items-center justify-between text-xs rounded"
|
|
159
157
|
>
|
|
160
158
|
<div className="flex items-center gap-2">
|
|
161
|
-
<TypeIcon className="w-3 h-3 text-
|
|
159
|
+
<TypeIcon className="w-3 h-3 text-(--slate-9)" />
|
|
162
160
|
<span className="font-mono">{column.name}</span>
|
|
163
161
|
</div>
|
|
164
162
|
<Badge
|
|
@@ -196,7 +194,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
196
194
|
<MetadataRow
|
|
197
195
|
label="Variable"
|
|
198
196
|
value={
|
|
199
|
-
<code className="text-xs bg-
|
|
197
|
+
<code className="text-xs bg-(--slate-4) px-1 rounded">
|
|
200
198
|
{table.variable_name}
|
|
201
199
|
</code>
|
|
202
200
|
}
|
|
@@ -207,7 +205,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
207
205
|
<MetadataRow
|
|
208
206
|
label="Engine"
|
|
209
207
|
value={
|
|
210
|
-
<code className="text-xs bg-
|
|
208
|
+
<code className="text-xs bg-(--slate-4) px-1 rounded">
|
|
211
209
|
{table.engine}
|
|
212
210
|
</code>
|
|
213
211
|
}
|
|
@@ -220,13 +218,13 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
220
218
|
<div className="grid grid-cols-2 gap-2 py-2">
|
|
221
219
|
{table.num_columns != null && (
|
|
222
220
|
<StatisticItem
|
|
223
|
-
icon={<ColumnIcon className="w-3 h-3 text-
|
|
221
|
+
icon={<ColumnIcon className="w-3 h-3 text-(--slate-9)" />}
|
|
224
222
|
text={`${table.num_columns} ${columnsText.pluralize(table.num_columns)}`}
|
|
225
223
|
/>
|
|
226
224
|
)}
|
|
227
225
|
{table.num_rows != null && (
|
|
228
226
|
<StatisticItem
|
|
229
|
-
icon={<HashIcon className="w-3 h-3 text-
|
|
227
|
+
icon={<HashIcon className="w-3 h-3 text-(--slate-9)" />}
|
|
230
228
|
text={`${table.num_rows} ${rowsText.pluralize(table.num_rows)}`}
|
|
231
229
|
/>
|
|
232
230
|
)}
|
|
@@ -242,8 +240,8 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
242
240
|
{hasPrimaryKeys && (
|
|
243
241
|
<div className="flex flex-row gap-1">
|
|
244
242
|
<div className="flex items-center gap-1">
|
|
245
|
-
<PrimaryKeyIcon className="w-3 h-3 text-
|
|
246
|
-
<span className="text-xs font-medium text-
|
|
243
|
+
<PrimaryKeyIcon className="w-3 h-3 text-(--amber-9)" />
|
|
244
|
+
<span className="text-xs font-medium text-(--slate-11)">
|
|
247
245
|
Primary Keys:
|
|
248
246
|
</span>
|
|
249
247
|
</div>
|
|
@@ -251,7 +249,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
251
249
|
<Badge
|
|
252
250
|
key={key}
|
|
253
251
|
variant="outline"
|
|
254
|
-
className="text-xs text-
|
|
252
|
+
className="text-xs text-(--slate-11)"
|
|
255
253
|
>
|
|
256
254
|
{key}
|
|
257
255
|
</Badge>
|
|
@@ -262,8 +260,8 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
262
260
|
{hasIndexes && (
|
|
263
261
|
<div className="flex flex-row gap-1">
|
|
264
262
|
<div className="flex items-center gap-1 mb-1">
|
|
265
|
-
<IndexIcon className="w-3 h-3 text-
|
|
266
|
-
<span className="text-xs font-medium text-
|
|
263
|
+
<IndexIcon className="w-3 h-3 text-(--purple-9)" />
|
|
264
|
+
<span className="text-xs font-medium text-(--slate-11)">
|
|
267
265
|
Indexes:
|
|
268
266
|
</span>
|
|
269
267
|
</div>
|
|
@@ -271,7 +269,7 @@ export const renderTableInfo = (table: DataTable): React.ReactNode => {
|
|
|
271
269
|
<Badge
|
|
272
270
|
key={index}
|
|
273
271
|
variant="outline"
|
|
274
|
-
className="text-xs text-
|
|
272
|
+
className="text-xs text-(--slate-11)"
|
|
275
273
|
>
|
|
276
274
|
{index}
|
|
277
275
|
</Badge>
|
|
@@ -303,10 +301,7 @@ export const renderColumnInfo = (column: DataTableColumn): React.ReactNode => {
|
|
|
303
301
|
|
|
304
302
|
const sampleItems =
|
|
305
303
|
column.sample_values?.map((value, index) => (
|
|
306
|
-
<div
|
|
307
|
-
key={index}
|
|
308
|
-
className="text-xs bg-[var(--slate-3)] rounded font-mono"
|
|
309
|
-
>
|
|
304
|
+
<div key={index} className="text-xs bg-(--slate-3) rounded font-mono">
|
|
310
305
|
{value === null || value === undefined ? "null" : String(value)}
|
|
311
306
|
</div>
|
|
312
307
|
)) || [];
|
|
@@ -314,7 +309,7 @@ export const renderColumnInfo = (column: DataTableColumn): React.ReactNode => {
|
|
|
314
309
|
return (
|
|
315
310
|
<div className={CONTAINER_STYLES}>
|
|
316
311
|
<SectionHeader
|
|
317
|
-
icon={<TypeIcon className="w-4 h-4 text-
|
|
312
|
+
icon={<TypeIcon className="w-4 h-4 text-(--slate-9)" />}
|
|
318
313
|
title={column.name}
|
|
319
314
|
badge={typeBadge}
|
|
320
315
|
/>
|
|
@@ -328,7 +323,7 @@ export const renderColumnInfo = (column: DataTableColumn): React.ReactNode => {
|
|
|
328
323
|
<MetadataRow
|
|
329
324
|
label="External Type"
|
|
330
325
|
value={
|
|
331
|
-
<code className="text-xs bg-
|
|
326
|
+
<code className="text-xs bg-(--slate-4) px-1 rounded">
|
|
332
327
|
{column.external_type}
|
|
333
328
|
</code>
|
|
334
329
|
}
|
|
@@ -349,10 +344,7 @@ export const renderColumnInfo = (column: DataTableColumn): React.ReactNode => {
|
|
|
349
344
|
|
|
350
345
|
export const renderDatabaseInfo = (database: Database): React.ReactNode => {
|
|
351
346
|
const dialectBadge = (
|
|
352
|
-
<Badge
|
|
353
|
-
variant="outline"
|
|
354
|
-
className="text-xs bg-[var(--blue-4)] text-[var(--blue-11)]"
|
|
355
|
-
>
|
|
347
|
+
<Badge variant="outline" className="text-xs bg-(--blue-4) text-(--blue-11)">
|
|
356
348
|
{database.dialect}
|
|
357
349
|
</Badge>
|
|
358
350
|
);
|
|
@@ -360,10 +352,10 @@ export const renderDatabaseInfo = (database: Database): React.ReactNode => {
|
|
|
360
352
|
const schemaItems = database.schemas.map((schema) => (
|
|
361
353
|
<div
|
|
362
354
|
key={schema.name}
|
|
363
|
-
className="flex items-center justify-between text-xs rounded hover:bg-
|
|
355
|
+
className="flex items-center justify-between text-xs rounded hover:bg-(--slate-3)"
|
|
364
356
|
>
|
|
365
357
|
<div className="flex items-center gap-2">
|
|
366
|
-
<SchemaIcon className="w-3 h-3 text-
|
|
358
|
+
<SchemaIcon className="w-3 h-3 text-(--slate-9)" />
|
|
367
359
|
<span>{schema.name}</span>
|
|
368
360
|
</div>
|
|
369
361
|
<Badge variant="outline" className="text-xs">
|
|
@@ -375,7 +367,7 @@ export const renderDatabaseInfo = (database: Database): React.ReactNode => {
|
|
|
375
367
|
return (
|
|
376
368
|
<div className={CONTAINER_STYLES}>
|
|
377
369
|
<SectionHeader
|
|
378
|
-
icon={<DatabaseIcon className="w-4 h-4 text-
|
|
370
|
+
icon={<DatabaseIcon className="w-4 h-4 text-(--blue-9)" />}
|
|
379
371
|
title={database.name}
|
|
380
372
|
badge={dialectBadge}
|
|
381
373
|
/>
|
|
@@ -390,7 +382,7 @@ export const renderDatabaseInfo = (database: Database): React.ReactNode => {
|
|
|
390
382
|
<MetadataRow
|
|
391
383
|
label="Engine"
|
|
392
384
|
value={
|
|
393
|
-
<code className="text-xs bg-
|
|
385
|
+
<code className="text-xs bg-(--slate-4) px-1 rounded">
|
|
394
386
|
{database.engine}
|
|
395
387
|
</code>
|
|
396
388
|
}
|
|
@@ -400,7 +392,7 @@ export const renderDatabaseInfo = (database: Database): React.ReactNode => {
|
|
|
400
392
|
{/* Schema Statistics */}
|
|
401
393
|
<div className="py-2">
|
|
402
394
|
<StatisticItem
|
|
403
|
-
icon={<SchemaIcon className="w-3 h-3 text-
|
|
395
|
+
icon={<SchemaIcon className="w-3 h-3 text-(--slate-9)" />}
|
|
404
396
|
text={`${database.schemas.length} schema${database.schemas.length === 1 ? "" : "s"}`}
|
|
405
397
|
/>
|
|
406
398
|
</div>
|
|
@@ -423,7 +415,7 @@ export const renderSchemaInfo = (schema: DatabaseSchema): React.ReactNode => {
|
|
|
423
415
|
const schemaBadge = (
|
|
424
416
|
<Badge
|
|
425
417
|
variant="outline"
|
|
426
|
-
className="text-xs bg-
|
|
418
|
+
className="text-xs bg-(--green-4) text-(--green-11)"
|
|
427
419
|
>
|
|
428
420
|
Schema
|
|
429
421
|
</Badge>
|
|
@@ -432,13 +424,13 @@ export const renderSchemaInfo = (schema: DatabaseSchema): React.ReactNode => {
|
|
|
432
424
|
const tableItems = schema.tables.map((table) => (
|
|
433
425
|
<div
|
|
434
426
|
key={table.name}
|
|
435
|
-
className="flex items-center justify-between text-xs rounded hover:bg-
|
|
427
|
+
className="flex items-center justify-between text-xs rounded hover:bg-(--slate-3)"
|
|
436
428
|
>
|
|
437
429
|
<div className="flex items-center gap-2">
|
|
438
430
|
{table.type === "view" ? (
|
|
439
|
-
<ViewIcon className="w-3 h-3 text-
|
|
431
|
+
<ViewIcon className="w-3 h-3 text-(--blue-9)" />
|
|
440
432
|
) : (
|
|
441
|
-
<TableIcon className="w-3 h-3 text-
|
|
433
|
+
<TableIcon className="w-3 h-3 text-(--green-9)" />
|
|
442
434
|
)}
|
|
443
435
|
<span>{table.name}</span>
|
|
444
436
|
</div>
|
|
@@ -446,8 +438,8 @@ export const renderSchemaInfo = (schema: DatabaseSchema): React.ReactNode => {
|
|
|
446
438
|
variant="outline"
|
|
447
439
|
className={`text-xs ${
|
|
448
440
|
table.type === "view"
|
|
449
|
-
? "bg-
|
|
450
|
-
: "bg-
|
|
441
|
+
? "bg-(--blue-4) text-(--blue-11)"
|
|
442
|
+
: "bg-(--green-4) text-(--green-11)"
|
|
451
443
|
}`}
|
|
452
444
|
>
|
|
453
445
|
{table.type}
|
|
@@ -458,7 +450,7 @@ export const renderSchemaInfo = (schema: DatabaseSchema): React.ReactNode => {
|
|
|
458
450
|
return (
|
|
459
451
|
<div className={CONTAINER_STYLES}>
|
|
460
452
|
<SectionHeader
|
|
461
|
-
icon={<SchemaIcon className="w-4 h-4 text-
|
|
453
|
+
icon={<SchemaIcon className="w-4 h-4 text-(--green-9)" />}
|
|
462
454
|
title={schema.name}
|
|
463
455
|
badge={schemaBadge}
|
|
464
456
|
/>
|
|
@@ -466,7 +458,7 @@ export const renderSchemaInfo = (schema: DatabaseSchema): React.ReactNode => {
|
|
|
466
458
|
{/* Table Statistics */}
|
|
467
459
|
<div className="py-2">
|
|
468
460
|
<StatisticItem
|
|
469
|
-
icon={<TableIcon className="w-3 h-3 text-
|
|
461
|
+
icon={<TableIcon className="w-3 h-3 text-(--slate-9)" />}
|
|
470
462
|
text={`${schema.tables.length} table${schema.tables.length === 1 ? "" : "s"}`}
|
|
471
463
|
/>
|
|
472
464
|
</div>
|
|
@@ -516,7 +508,7 @@ export const renderDatasourceInfo = (
|
|
|
516
508
|
.map((table) => {
|
|
517
509
|
return (
|
|
518
510
|
<div key={table.name} className="flex items-center gap-2 ml-4">
|
|
519
|
-
<TableIcon className="w-3 h-3 text-
|
|
511
|
+
<TableIcon className="w-3 h-3 text-(--green-9)" />
|
|
520
512
|
<span className="text-xs">{table.name}</span>
|
|
521
513
|
</div>
|
|
522
514
|
);
|
|
@@ -525,8 +517,8 @@ export const renderDatasourceInfo = (
|
|
|
525
517
|
|
|
526
518
|
return (
|
|
527
519
|
<div key={schema.name}>
|
|
528
|
-
<div className="flex items-center gap-2 text-xs rounded hover:bg-
|
|
529
|
-
<SchemaIcon className="w-3 h-3 text-
|
|
520
|
+
<div className="flex items-center gap-2 text-xs rounded hover:bg-(--slate-3) ml-2">
|
|
521
|
+
<SchemaIcon className="w-3 h-3 text-(--slate-9)" />
|
|
530
522
|
<span>{schema.name}</span>
|
|
531
523
|
{isDefaultSchema && DefaultBadge}
|
|
532
524
|
<Badge variant="outline" className="text-xs ml-auto">
|
|
@@ -554,7 +546,7 @@ export const renderDatasourceInfo = (
|
|
|
554
546
|
return (
|
|
555
547
|
<div key={db.name}>
|
|
556
548
|
<div className="flex items-center gap-2">
|
|
557
|
-
<DatabaseIcon className="w-3 h-3 text-
|
|
549
|
+
<DatabaseIcon className="w-3 h-3 text-(--blue-9)" />
|
|
558
550
|
<span className="text-xs">{db.name}</span>
|
|
559
551
|
{isDefaultDb && DefaultBadge}
|
|
560
552
|
</div>
|
|
@@ -572,7 +564,7 @@ export const renderDatasourceInfo = (
|
|
|
572
564
|
|
|
573
565
|
const dataframeItems = dataframes?.map((table) => (
|
|
574
566
|
<div key={table.name} className="flex items-center gap-2">
|
|
575
|
-
<TableIcon className="w-3 h-3 text-
|
|
567
|
+
<TableIcon className="w-3 h-3 text-(--blue-9)" />
|
|
576
568
|
<span className="text-xs">{table.name}</span>
|
|
577
569
|
</div>
|
|
578
570
|
));
|
|
@@ -580,7 +572,7 @@ export const renderDatasourceInfo = (
|
|
|
580
572
|
return (
|
|
581
573
|
<div className={`${CONTAINER_STYLES} px-1`}>
|
|
582
574
|
<SectionHeader
|
|
583
|
-
icon={<DatasourceIcon className="w-4 h-4 text-
|
|
575
|
+
icon={<DatasourceIcon className="w-4 h-4 text-(--purple-9)" />}
|
|
584
576
|
title={title}
|
|
585
577
|
/>
|
|
586
578
|
|
|
@@ -599,7 +591,7 @@ export const renderDatasourceInfo = (
|
|
|
599
591
|
value={
|
|
600
592
|
<Badge
|
|
601
593
|
variant="outline"
|
|
602
|
-
className="text-xs bg-
|
|
594
|
+
className="text-xs bg-(--green-4) text-(--green-11)"
|
|
603
595
|
>
|
|
604
596
|
{connection.source}
|
|
605
597
|
</Badge>
|
|
@@ -610,11 +602,11 @@ export const renderDatasourceInfo = (
|
|
|
610
602
|
{/* Statistics */}
|
|
611
603
|
<div className="flex flex-row justify-between py-2">
|
|
612
604
|
<StatisticItem
|
|
613
|
-
icon={<DatabaseIcon className="w-3 h-3 text-
|
|
605
|
+
icon={<DatabaseIcon className="w-3 h-3 text-(--slate-9)" />}
|
|
614
606
|
text={`${databaseCount} ${databasesText.pluralize(databaseCount)}`}
|
|
615
607
|
/>
|
|
616
608
|
<StatisticItem
|
|
617
|
-
icon={<SchemaIcon className="w-3 h-3 text-
|
|
609
|
+
icon={<SchemaIcon className="w-3 h-3 text-(--slate-9)" />}
|
|
618
610
|
text={`${schemasCount} ${schemasText.pluralize(schemasCount)}`}
|
|
619
611
|
/>
|
|
620
612
|
</div>
|
|
@@ -641,10 +633,10 @@ export const renderEmptyInfo = (
|
|
|
641
633
|
) => {
|
|
642
634
|
return (
|
|
643
635
|
<div className="flex items-start gap-2 mt-3">
|
|
644
|
-
<InfoIcon size={10} className="mt-1 text-
|
|
645
|
-
<span className="text-xs text-
|
|
636
|
+
<InfoIcon size={10} className="mt-1 text-(--slate-10) shrink-0" />
|
|
637
|
+
<span className="text-xs text-(--slate-11)">
|
|
646
638
|
No {type} information available.{" \n"}
|
|
647
|
-
<span className="text-
|
|
639
|
+
<span className="text-(--blue-10)">
|
|
648
640
|
Introspect to see more details.
|
|
649
641
|
</span>
|
|
650
642
|
</span>
|
|
@@ -640,6 +640,60 @@ def run(polars):
|
|
|
640
640
|
`);
|
|
641
641
|
});
|
|
642
642
|
|
|
643
|
+
test("set comprehension target shadows outer global", () => {
|
|
644
|
+
// Regression: SCOPE_CREATING_NODES used "SetComprehension" instead of the
|
|
645
|
+
// grammar's "SetComprehensionExpression", so set comprehensions never
|
|
646
|
+
// created a scope and their for-target was treated as reactive.
|
|
647
|
+
expect(runHighlight(["x"], "result = {x for x in range(5)}"))
|
|
648
|
+
.toMatchInlineSnapshot(`
|
|
649
|
+
"
|
|
650
|
+
result = {x for x in range(5)}
|
|
651
|
+
"
|
|
652
|
+
`);
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
test("from-import module path stays reactive", () => {
|
|
656
|
+
// Regression: ImportStatement collected every VariableName child, so the
|
|
657
|
+
// module name in `from m import y` was wrongly treated as a local binding.
|
|
658
|
+
expect(
|
|
659
|
+
runHighlight(
|
|
660
|
+
["math"],
|
|
661
|
+
`
|
|
662
|
+
def f():
|
|
663
|
+
from math import sin as my_sin
|
|
664
|
+
return math + my_sin(1)`,
|
|
665
|
+
),
|
|
666
|
+
).toMatchInlineSnapshot(`
|
|
667
|
+
"
|
|
668
|
+
def f():
|
|
669
|
+
from math import sin as my_sin
|
|
670
|
+
return math + my_sin(1)
|
|
671
|
+
^^^^
|
|
672
|
+
"
|
|
673
|
+
`);
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
test("from-import: aliased imported name is not a binding", () => {
|
|
677
|
+
// Regression: `sin` in `from math import sin as my_sin` was incorrectly
|
|
678
|
+
// registered as a local binding, hiding genuine reactive uses of `sin`.
|
|
679
|
+
expect(
|
|
680
|
+
runHighlight(
|
|
681
|
+
["sin"],
|
|
682
|
+
`
|
|
683
|
+
def f():
|
|
684
|
+
from math import sin as my_sin
|
|
685
|
+
return sin + my_sin(1)`,
|
|
686
|
+
),
|
|
687
|
+
).toMatchInlineSnapshot(`
|
|
688
|
+
"
|
|
689
|
+
def f():
|
|
690
|
+
from math import sin as my_sin
|
|
691
|
+
return sin + my_sin(1)
|
|
692
|
+
^^^
|
|
693
|
+
"
|
|
694
|
+
`);
|
|
695
|
+
});
|
|
696
|
+
|
|
643
697
|
test("lambda inside function with outer global", () => {
|
|
644
698
|
expect(
|
|
645
699
|
runHighlight(
|
|
@@ -16,7 +16,7 @@ const SCOPE_CREATING_NODES = new Set([
|
|
|
16
16
|
"FunctionDefinition",
|
|
17
17
|
"LambdaExpression",
|
|
18
18
|
"ArrayComprehensionExpression",
|
|
19
|
-
"
|
|
19
|
+
"SetComprehensionExpression",
|
|
20
20
|
"DictionaryComprehensionExpression",
|
|
21
21
|
"ComprehensionExpression",
|
|
22
22
|
"ClassDefinition",
|
|
@@ -152,7 +152,7 @@ export function findReactiveVariables(options: {
|
|
|
152
152
|
}
|
|
153
153
|
case "ArrayComprehensionExpression":
|
|
154
154
|
case "DictionaryComprehensionExpression":
|
|
155
|
-
case "
|
|
155
|
+
case "SetComprehensionExpression":
|
|
156
156
|
case "ComprehensionExpression": {
|
|
157
157
|
// Domprehension variables - look for VariableName or TupleExpression after 'for'
|
|
158
158
|
const subCursor = node.cursor();
|
|
@@ -276,49 +276,52 @@ export function findReactiveVariables(options: {
|
|
|
276
276
|
break;
|
|
277
277
|
}
|
|
278
278
|
case "ImportStatement": {
|
|
279
|
-
//
|
|
279
|
+
// The grammar emits a single ImportStatement for both `import x [as y]`
|
|
280
|
+
// and `from m import x [as y], ...`. Direct children mix keywords,
|
|
281
|
+
// module-path names (before `import`), imported names, and aliases.
|
|
282
|
+
// Only post-`import` names that aren't shadowed by a following `as`
|
|
283
|
+
// (and the alias itself when `as` is present) bind in the current
|
|
284
|
+
// scope.
|
|
280
285
|
const subCursor = node.cursor();
|
|
281
286
|
subCursor.firstChild();
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
allDeclarations.get(currentScope)?.add(varName);
|
|
287
|
+
const currentScope =
|
|
288
|
+
currentScopeStack[currentScopeStack.length - 1] ?? -1;
|
|
289
|
+
if (!allDeclarations.has(currentScope)) {
|
|
290
|
+
allDeclarations.set(currentScope, new Set());
|
|
291
|
+
}
|
|
292
|
+
const scope = allDeclarations.get(currentScope);
|
|
293
|
+
let pastImport = false;
|
|
294
|
+
let pending: string | null = null;
|
|
295
|
+
const commit = () => {
|
|
296
|
+
if (pending !== null) {
|
|
297
|
+
scope?.add(pending);
|
|
295
298
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
break;
|
|
299
|
-
}
|
|
300
|
-
case "ImportFromStatement": {
|
|
301
|
-
// Handle from x import y as z
|
|
302
|
-
const subCursor = node.cursor();
|
|
303
|
-
subCursor.firstChild();
|
|
304
|
-
let foundImport = false;
|
|
299
|
+
pending = null;
|
|
300
|
+
};
|
|
305
301
|
do {
|
|
306
302
|
if (subCursor.name === "import") {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
303
|
+
pastImport = true;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (!pastImport) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (subCursor.name === "as") {
|
|
310
|
+
// Drop the imported name; the next VariableName is the alias.
|
|
311
|
+
pending = null;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (subCursor.name === "VariableName") {
|
|
315
|
+
commit();
|
|
316
|
+
pending = options.state.doc.sliceString(
|
|
310
317
|
subCursor.from,
|
|
311
318
|
subCursor.to,
|
|
312
319
|
);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
currentScopeStack[currentScopeStack.length - 1] ?? -1;
|
|
316
|
-
if (!allDeclarations.has(currentScope)) {
|
|
317
|
-
allDeclarations.set(currentScope, new Set());
|
|
318
|
-
}
|
|
319
|
-
allDeclarations.get(currentScope)?.add(varName);
|
|
320
|
+
} else if (subCursor.name === ",") {
|
|
321
|
+
commit();
|
|
320
322
|
}
|
|
321
323
|
} while (subCursor.nextSibling());
|
|
324
|
+
commit();
|
|
322
325
|
|
|
323
326
|
break;
|
|
324
327
|
}
|
|
@@ -424,6 +427,12 @@ export function findReactiveVariables(options: {
|
|
|
424
427
|
const nodeName = cursor.name;
|
|
425
428
|
const nodeStart = cursor.from;
|
|
426
429
|
|
|
430
|
+
// Names inside an import statement are module paths, imported names, or
|
|
431
|
+
// aliases — none of them are reactive *uses* of an outer-cell global.
|
|
432
|
+
if (nodeName === "ImportStatement") {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
|
|
427
436
|
const isNewScope = SCOPE_CREATING_NODES.has(nodeName);
|
|
428
437
|
|
|
429
438
|
let currentScopeStack = scopeStack;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type Base64String = components["schemas"]["Base64String"];
|
|
13
13
|
interface TestIslandApp {
|
|
14
14
|
id: string;
|
|
15
|
+
payloadBacked?: boolean;
|
|
15
16
|
cells: { code: string; idx: number; output: string }[];
|
|
16
17
|
}
|
|
17
18
|
interface TestExportContext {
|
|
@@ -142,6 +143,30 @@ describe("IslandsPyodideBridge", () => {
|
|
|
142
143
|
});
|
|
143
144
|
});
|
|
144
145
|
|
|
146
|
+
it("should ignore trusted export notebook code for a payload-backed app", async () => {
|
|
147
|
+
const payloadApp = {
|
|
148
|
+
id: "app-1",
|
|
149
|
+
payloadBacked: true,
|
|
150
|
+
cells: [{ code: "x = 1", idx: 0, output: "<div>1</div>" }],
|
|
151
|
+
};
|
|
152
|
+
mockParseMarimoIslandApps.mockReturnValue([payloadApp]);
|
|
153
|
+
mockGetMarimoExportContext.mockReturnValue({
|
|
154
|
+
trusted: true,
|
|
155
|
+
notebookCode: "full notebook should be ignored",
|
|
156
|
+
});
|
|
157
|
+
mockCreateMarimoFile.mockReturnValue("generated payload app");
|
|
158
|
+
|
|
159
|
+
await (
|
|
160
|
+
bridge as unknown as { startSessionsForAllApps(): Promise<void> }
|
|
161
|
+
).startSessionsForAllApps();
|
|
162
|
+
|
|
163
|
+
expect(mockCreateMarimoFile).toHaveBeenCalledWith(payloadApp);
|
|
164
|
+
expect(mockStartSessionRequest).toHaveBeenCalledWith({
|
|
165
|
+
appId: "app-1",
|
|
166
|
+
code: "generated payload app",
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
145
170
|
it("should keep synthesized per-app files for multiple reactive apps even when export context exists", async () => {
|
|
146
171
|
mockParseMarimoIslandApps.mockReturnValue([
|
|
147
172
|
{
|