@marimo-team/islands 0.16.1 → 0.16.3
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-DyqLQGPc.js → ConnectedDataExplorerComponent-CareOso9.js} +2 -2
- package/dist/{ImageComparisonComponent-CQDGJfUA.js → ImageComparisonComponent-I_Z738Uj.js} +1 -1
- package/dist/{_baseUniq-B2Nna6Kt.js → _baseUniq-D-Kb4EU4.js} +1 -1
- package/dist/{any-language-editor-D-wq0tOG.js → any-language-editor-BRWmYor8.js} +1 -1
- package/dist/{architectureDiagram-W76B3OCA-C6tdnMBf.js → architectureDiagram-W76B3OCA-bZJcJYGH.js} +4 -4
- package/dist/assets/{worker-B0C57BK8.js → worker-DMlIUTIq.js} +18 -17
- package/dist/{blockDiagram-QIGZ2CNN-IagL8LCN.js → blockDiagram-QIGZ2CNN-DyXjO8fR.js} +5 -5
- package/dist/{c4Diagram-FPNF74CW-D3_lIWUP.js → c4Diagram-FPNF74CW-Bfs9ui2r.js} +2 -2
- package/dist/{channel-DCJI_DKk.js → channel-CMup9X3Z.js} +1 -1
- package/dist/{chunk-4BX2VUAB-B2DrODwN.js → chunk-4BX2VUAB-CW-ni6M_.js} +1 -1
- package/dist/{chunk-55IACEB6-BUWDsQ-t.js → chunk-55IACEB6-Bj-Indya.js} +1 -1
- package/dist/{chunk-FMBD7UC4-BExPNFv1.js → chunk-FMBD7UC4-9IC8qSSk.js} +1 -1
- package/dist/{chunk-K7UQS3LO-Cixi-Yko.js → chunk-K7UQS3LO-aapkEuWN.js} +4 -4
- package/dist/{chunk-QN33PNHL-B83MtvER.js → chunk-QN33PNHL-Bo5dJ5T5.js} +1 -1
- package/dist/{chunk-QZHKN3VN-CXvbu85X.js → chunk-QZHKN3VN-BkMzjJYY.js} +1 -1
- package/dist/{chunk-TVAH2DTR-CpiumCHg.js → chunk-TVAH2DTR-Wqy_C_Rn.js} +3 -3
- package/dist/{chunk-TZMSLE5B-DIzaZjcI.js → chunk-TZMSLE5B-DjBmEAUz.js} +1 -1
- package/dist/{classDiagram-v2-RKCZMP56-DyN5HPdk.js → classDiagram-KNZD7YFC-DUsaN1O4.js} +2 -2
- package/dist/{classDiagram-KNZD7YFC-DyN5HPdk.js → classDiagram-v2-RKCZMP56-DUsaN1O4.js} +2 -2
- package/dist/{clone-DrJYap2i.js → clone-Dkt_7KOK.js} +1 -1
- package/dist/{cose-bilkent-S5V4N54A-D39b4WrQ.js → cose-bilkent-S5V4N54A-ClBuGZWI.js} +2 -2
- package/dist/{dagre-5GWH7T2D-BLjRxDpS.js → dagre-5GWH7T2D-BzmDIGaM.js} +6 -6
- package/dist/{data-grid-overlay-editor-DTALqerV.js → data-grid-overlay-editor-NiU9Ea77.js} +2 -2
- package/dist/{diagram-N5W7TBWH-MM8AIKGR.js → diagram-N5W7TBWH-BlO1yw_g.js} +5 -5
- package/dist/{diagram-QEK2KX5R-BZGarWuJ.js → diagram-QEK2KX5R-BvK83LUx.js} +3 -3
- package/dist/{diagram-S2PKOQOG-CnPinN9Q.js → diagram-S2PKOQOG-DvBzRYd7.js} +3 -3
- package/dist/{dockerfile-U8DnCJ4X.js → dockerfile-CPQG2tLO.js} +1 -1
- package/dist/{erDiagram-AWTI2OKA-CvDVbxOO.js → erDiagram-AWTI2OKA-Doy9FRTX.js} +4 -4
- package/dist/{flowDiagram-PVAE7QVJ-C2uuBTZS.js → flowDiagram-PVAE7QVJ-D_tX_HU1.js} +5 -5
- package/dist/{ganttDiagram-OWAHRB6G-BEff10RF.js → ganttDiagram-OWAHRB6G-CV03BHVY.js} +4 -4
- package/dist/{gitGraphDiagram-NY62KEGX-wggu0kb2.js → gitGraphDiagram-NY62KEGX-w3szEguZ.js} +4 -4
- package/dist/{glide-data-editor-Bqh5_dzJ.js → glide-data-editor-akznFrmp.js} +3 -3
- package/dist/{graph-DKpp_wzf.js → graph-CjrrDHdT.js} +3 -3
- package/dist/index-CIJJs0Tu.js +40382 -0
- package/dist/{index-DzJ_YPCG.js → index-DMo6cbcV.js} +3 -3
- package/dist/{index-4XruEJkp.js → index-DlV2CtJb.js} +1 -1
- package/dist/{index-DdfF_cLK.js → index-Y-Vbae6Z.js} +1 -1
- package/dist/{infoDiagram-STP46IZ2-DF7KW-Op.js → infoDiagram-STP46IZ2-BcBV2j75.js} +2 -2
- package/dist/{journeyDiagram-BIP6EPQ6-B_jmhmqd.js → journeyDiagram-BIP6EPQ6-BTGMSgvB.js} +3 -3
- package/dist/{kanban-definition-6OIFK2YF-B-M9FTyw.js → kanban-definition-6OIFK2YF-aopNqZ1Y.js} +2 -2
- package/dist/{layout-C4oVYZZD.js → layout-Dvo9pb_w.js} +4 -4
- package/dist/{linear-C-HCGr0T.js → linear-CHnELER9.js} +1 -1
- package/dist/{main-B9x2-9f2.js → main-kLZGkzVQ.js} +41787 -40423
- package/dist/main.js +1 -1
- package/dist/{mermaid-BE4cM3Qs.js → mermaid-DgM4_4bD.js} +30 -30
- package/dist/{min-DTpHJ698.js → min-cX4DuL_n.js} +2 -2
- package/dist/{mindmap-definition-Q6HEUPPD-Cpd-hO1E.js → mindmap-definition-Q6HEUPPD-DZjbYryy.js} +3 -3
- package/dist/{number-overlay-editor-CvURA2Ud.js → number-overlay-editor-8MpIObf7.js} +2 -2
- package/dist/{pieDiagram-ADFJNKIX-D9f_f6fn.js → pieDiagram-ADFJNKIX-D6L1IYAc.js} +3 -3
- package/dist/{quadrantDiagram-LMRXKWRM-DgllE7xw.js → quadrantDiagram-LMRXKWRM-nOyuc3Bf.js} +2 -2
- package/dist/{react-plotly-BU-JRJSi.js → react-plotly-ChkfYiVe.js} +1 -1
- package/dist/{requirementDiagram-4UW4RH46-Dk_G8eUb.js → requirementDiagram-4UW4RH46-OVV8wsju.js} +3 -3
- package/dist/{sankeyDiagram-GR3RE2ED-BhLIhDc1.js → sankeyDiagram-GR3RE2ED-qZHMdnE_.js} +1 -1
- package/dist/{sequenceDiagram-C3RYC4MD-DHoZdMFJ.js → sequenceDiagram-C3RYC4MD-D0bOqf-t.js} +3 -3
- package/dist/{slides-component-DXAgdf7K.js → slides-component-CNzLDdA3.js} +1 -1
- package/dist/{stateDiagram-KXAO66HF-C1Ie-7Xf.js → stateDiagram-KXAO66HF-CFNCnNJS.js} +4 -4
- package/dist/{stateDiagram-v2-UMBNRL4Z--CRuIHtM.js → stateDiagram-v2-UMBNRL4Z-CnIh27m8.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{time-yQjlGPwa.js → time-Z7CJSfOW.js} +2 -2
- package/dist/{timeline-definition-XQNQX7LJ-D_PjxB1B.js → timeline-definition-XQNQX7LJ-BYLMfrvK.js} +1 -1
- package/dist/{treemap-75Q7IDZK--NYqQjUZ.js → treemap-75Q7IDZK-BEh1HacP.js} +5 -5
- package/dist/{vega-component-CCUOMM5K.js → vega-component-iMjXd3tD.js} +2 -2
- package/dist/{xychartDiagram-6GGTOJPD-WLKsEnzs.js → xychartDiagram-6GGTOJPD-Bmi13ZSG.js} +2 -2
- package/package.json +8 -8
- package/src/__mocks__/common.ts +5 -3
- package/src/__mocks__/notebook.ts +2 -2
- package/src/__mocks__/requests.ts +1 -0
- package/src/__tests__/main.test.tsx +2 -2
- package/src/components/ai/ai-provider-icon.tsx +2 -0
- package/src/components/app-config/ai-config.tsx +32 -1
- package/src/components/app-config/common.tsx +2 -2
- package/src/components/app-config/user-config-form.tsx +26 -0
- package/src/components/audio/audio-recorder.tsx +0 -1
- package/src/components/chat/acp/blocks.tsx +2 -2
- package/src/components/chat/acp/thread.tsx +3 -5
- package/src/components/chat/acp/utils.ts +5 -5
- package/src/components/chat/chat-panel.tsx +1 -1
- package/src/components/data-table/__tests__/columns.test.tsx +38 -0
- package/src/components/data-table/__tests__/data-table.test.tsx +2 -2
- package/src/components/data-table/cell-hover-template/feature.ts +1 -1
- package/src/components/data-table/cell-hover-template/types.ts +1 -1
- package/src/components/data-table/charts/__tests__/altair-generator.test.ts +1 -1
- package/src/components/data-table/charts/chart-spec/tooltips.ts +3 -3
- package/src/components/data-table/charts/components/chart-items.tsx +1 -1
- package/src/components/data-table/charts/components/form-fields.tsx +2 -2
- package/src/components/data-table/charts/constants.ts +1 -1
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +2 -2
- package/src/components/data-table/columns.tsx +22 -3
- package/src/components/data-table/data-table.tsx +35 -3
- package/src/components/data-table/date-popover.tsx +1 -1
- package/src/components/data-table/download-actions.tsx +1 -1
- package/src/components/data-table/range-focus/__tests__/utils.test.ts +5 -5
- package/src/components/data-table/renderers.tsx +22 -13
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
- package/src/components/data-table/schemas.ts +16 -0
- package/src/components/data-table/types.ts +4 -3
- package/src/components/datasources/column-preview.tsx +9 -6
- package/src/components/debugger/debugger-code.tsx +1 -1
- package/src/components/dependency-graph/custom-node.tsx +15 -6
- package/src/components/dependency-graph/dependency-graph-minimap.tsx +2 -2
- package/src/components/dependency-graph/dependency-graph-tree.tsx +2 -2
- package/src/components/dependency-graph/dependency-graph.tsx +1 -1
- package/src/components/dependency-graph/elements.ts +7 -7
- package/src/components/dependency-graph/utils/changes.ts +4 -4
- package/src/components/editor/Cell.tsx +7 -1
- package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
- package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +1 -1
- package/src/components/editor/chrome/panels/packages-panel.tsx +1 -1
- package/src/components/editor/columns/storage.ts +1 -1
- package/src/components/editor/database/__tests__/__snapshots__/as-code.test.ts.snap +36 -0
- package/src/components/editor/database/__tests__/as-code.test.ts +30 -7
- package/src/components/editor/database/add-database-form.tsx +11 -0
- package/src/components/editor/database/as-code.ts +104 -5
- package/src/components/editor/database/schemas.ts +36 -18
- package/src/components/editor/errors/auto-fix.tsx +12 -2
- package/src/components/editor/errors/sql-validation-errors.tsx +40 -0
- package/src/components/editor/navigation/clipboard.ts +2 -2
- package/src/components/editor/output/ConsoleOutput.tsx +14 -2
- package/src/components/editor/output/JsonOutput.tsx +1 -1
- package/src/components/editor/output/MarimoErrorOutput.tsx +60 -1
- package/src/components/editor/output/MarimoTracebackOutput.tsx +17 -2
- package/src/components/editor/renderers/grid-layout/types.ts +2 -2
- package/src/components/editor/renderers/plugins.ts +1 -1
- package/src/components/editor/renderers/types.ts +1 -1
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +7 -7
- package/src/components/forms/form.tsx +5 -5
- package/src/components/ui/links.tsx +1 -0
- package/src/core/ai/__tests__/model-registry.test.ts +0 -10
- package/src/core/ai/context/providers/cell-output.ts +1 -18
- package/src/core/ai/context/providers/error.ts +2 -2
- package/src/core/ai/ids/ids.ts +1 -0
- package/src/core/ai/model-registry.ts +2 -1
- package/src/core/cells/cells.ts +5 -5
- package/src/core/cells/logs.ts +1 -1
- package/src/core/cells/types.ts +1 -1
- package/src/core/codemirror/__tests__/format.test.ts +6 -0
- package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
- package/src/core/codemirror/editing/commands.ts +2 -2
- package/src/core/codemirror/find-replace/navigate.ts +1 -1
- package/src/core/codemirror/language/__tests__/extension.test.ts +24 -0
- package/src/core/codemirror/language/__tests__/sql-validation.test.ts +133 -0
- package/src/core/codemirror/language/__tests__/sql.test.ts +764 -79
- package/src/core/codemirror/language/languages/markdown.ts +4 -1
- package/src/core/codemirror/language/languages/sql/banner-validation-errors.ts +85 -0
- package/src/core/codemirror/language/languages/sql/completion-builder.ts +160 -0
- package/src/core/codemirror/language/languages/sql/completion-sources.tsx +9 -3
- package/src/core/codemirror/language/languages/sql/completion-store.ts +46 -50
- package/src/core/codemirror/language/languages/sql/renderers.tsx +485 -0
- package/src/core/codemirror/language/languages/sql/sql-mode.ts +20 -0
- package/src/core/codemirror/language/languages/sql/sql.ts +218 -4
- package/src/core/codemirror/language/languages/sql/utils.ts +4 -1
- package/src/core/codemirror/language/panel/panel.tsx +8 -2
- package/src/core/codemirror/language/panel/sql.tsx +86 -4
- package/src/core/codemirror/language/utils/ast.ts +3 -3
- package/src/core/codemirror/lsp/federated-lsp.ts +4 -4
- package/src/core/codemirror/lsp/lens.ts +4 -4
- package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
- package/src/core/codemirror/lsp/types.ts +1 -1
- package/src/core/codemirror/markdown/completions.ts +1 -1
- package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
- package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/config/feature-flag.tsx +6 -2
- package/src/core/datasets/request-registry.ts +24 -1
- package/src/core/dom/events.ts +1 -1
- package/src/core/dom/outline.ts +2 -2
- package/src/core/dom/uiregistry.ts +2 -8
- package/src/core/errors/__tests__/errors.test.ts +22 -4
- package/src/core/errors/errors.ts +29 -1
- package/src/core/errors/state.ts +1 -1
- package/src/core/islands/bridge.ts +1 -0
- package/src/core/islands/main.ts +3 -2
- package/src/core/islands/parse.ts +1 -3
- package/src/core/kernel/messages.ts +2 -1
- package/src/core/network/CachingRequestRegistry.ts +74 -0
- package/src/core/network/DeferredRequestRegistry.ts +3 -1
- package/src/core/network/__tests__/CachingRequestRegistry.test.ts +73 -0
- package/src/core/network/requests-network.ts +7 -0
- package/src/core/network/requests-static.ts +1 -0
- package/src/core/network/requests-toasting.ts +1 -0
- package/src/core/network/types.ts +3 -1
- package/src/core/variables/state.ts +2 -2
- package/src/core/wasm/__tests__/state.test.ts +1 -1
- package/src/core/wasm/bridge.ts +5 -0
- package/src/core/websocket/useMarimoWebSocket.tsx +9 -2
- package/src/custom.d.ts +1 -1
- package/src/hooks/useCellRenderCount.ts +1 -0
- package/src/hooks/useResizeHandle.ts +4 -1
- package/src/plugins/core/RenderHTML.tsx +1 -2
- package/src/plugins/core/registerReactComponent.tsx +23 -19
- package/src/plugins/impl/DataTablePlugin.tsx +18 -6
- package/src/plugins/impl/FileUploadPlugin.tsx +1 -1
- package/src/plugins/impl/RefreshPlugin.tsx +1 -1
- package/src/plugins/impl/SliderPlugin.tsx +4 -0
- package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +27 -9
- package/src/plugins/impl/anywidget/__tests__/AnyWidgetPlugin.test.tsx +58 -2
- package/src/plugins/impl/anywidget/__tests__/model.test.ts +3 -4
- package/src/plugins/impl/anywidget/model.ts +2 -3
- package/src/plugins/impl/data-editor/types.ts +1 -1
- package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +17 -5
- package/src/plugins/impl/data-frames/types.ts +1 -1
- package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
- package/src/plugins/impl/vega/__tests__/loader.test.ts +2 -2
- package/src/plugins/impl/vega/loader.ts +1 -1
- package/src/plugins/impl/vega/vega-component.tsx +1 -1
- package/src/plugins/impl/vega/vega-loader.ts +2 -2
- package/src/plugins/layout/NavigationMenuPlugin.tsx +1 -1
- package/src/plugins/layout/RoutesPlugin.tsx +1 -2
- package/src/plugins/plugins.ts +2 -2
- package/src/stories/dataframe.stories.tsx +2 -0
- package/src/utils/Logger.ts +1 -1
- package/src/utils/__tests__/data-views.test.ts +30 -68
- package/src/utils/__tests__/dom.test.ts +167 -0
- package/src/utils/__tests__/id-tree.test.ts +49 -1
- package/src/utils/__tests__/storage.test.ts +1 -1
- package/src/utils/__tests__/traceback.test.ts +13 -2
- package/src/utils/arrays.ts +1 -1
- package/src/utils/createReducer.ts +1 -5
- package/src/utils/data-views.ts +6 -19
- package/src/utils/dom.ts +55 -0
- package/src/utils/edit-distance.ts +1 -1
- package/src/utils/fileToBase64.ts +1 -1
- package/src/utils/id-tree.tsx +20 -18
- package/src/utils/json/base64.ts +13 -0
- package/src/utils/json/json-parser.ts +2 -2
- package/src/utils/lru.ts +4 -0
- package/src/utils/mergeRefs.ts +1 -1
- package/src/utils/objects.ts +3 -3
- package/src/utils/pluralize.ts +1 -1
- package/src/utils/routes.ts +2 -2
- package/src/utils/sets.ts +1 -1
- package/src/utils/traceback.ts +45 -15
- package/src/utils/tracer.ts +11 -9
- package/dist/index-DW0BCGJE.js +0 -40315
- package/src/__tests__/lru.test.ts +0 -74
|
@@ -17,6 +17,7 @@ import { JsonOutput } from "../editor/output/JsonOutput";
|
|
|
17
17
|
import { Button } from "../ui/button";
|
|
18
18
|
import { Checkbox } from "../ui/checkbox";
|
|
19
19
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
|
20
|
+
import { Tooltip } from "../ui/tooltip";
|
|
20
21
|
import { DataTableColumnHeader } from "./column-header";
|
|
21
22
|
import type { ColumnChartSpecModel } from "./column-summary/chart-spec-model";
|
|
22
23
|
import { TableColumnSummary } from "./column-summary/column-summary";
|
|
@@ -103,6 +104,7 @@ export function generateColumns<T>({
|
|
|
103
104
|
chartSpecModel,
|
|
104
105
|
textJustifyColumns,
|
|
105
106
|
wrappedColumns,
|
|
107
|
+
headerTooltip,
|
|
106
108
|
showDataTypes,
|
|
107
109
|
calculateTopKRows,
|
|
108
110
|
}: {
|
|
@@ -112,9 +114,10 @@ export function generateColumns<T>({
|
|
|
112
114
|
chartSpecModel?: ColumnChartSpecModel<unknown>;
|
|
113
115
|
textJustifyColumns?: Record<string, "left" | "center" | "right">;
|
|
114
116
|
wrappedColumns?: string[];
|
|
117
|
+
headerTooltip?: Record<string, string>;
|
|
115
118
|
showDataTypes?: boolean;
|
|
116
119
|
calculateTopKRows?: CalculateTopKRows;
|
|
117
|
-
}):
|
|
120
|
+
}): ColumnDef<T>[] {
|
|
118
121
|
// Row-headers are typically index columns
|
|
119
122
|
const rowHeadersSet = new Set(rowHeaders.map(([columnName]) => columnName));
|
|
120
123
|
|
|
@@ -165,6 +168,7 @@ export function generateColumns<T>({
|
|
|
165
168
|
header: ({ column }) => {
|
|
166
169
|
const stats = chartSpecModel?.getColumnStats(key);
|
|
167
170
|
const dtype = column.columnDef.meta?.dtype;
|
|
171
|
+
const headerTitle = headerTooltip?.[key];
|
|
168
172
|
const dtypeHeader =
|
|
169
173
|
showDataTypes && dtype ? (
|
|
170
174
|
<div className="flex flex-row gap-1">
|
|
@@ -179,14 +183,29 @@ export function generateColumns<T>({
|
|
|
179
183
|
|
|
180
184
|
const headerWithType = (
|
|
181
185
|
<div className="flex flex-col">
|
|
182
|
-
<span
|
|
186
|
+
<span
|
|
187
|
+
className={cn(
|
|
188
|
+
"font-bold",
|
|
189
|
+
headerTitle && "underline decoration-dotted",
|
|
190
|
+
)}
|
|
191
|
+
>
|
|
192
|
+
{key === "" ? " " : key}
|
|
193
|
+
</span>
|
|
183
194
|
{dtypeHeader}
|
|
184
195
|
</div>
|
|
185
196
|
);
|
|
186
197
|
|
|
198
|
+
const headerWithTooltip = headerTitle ? (
|
|
199
|
+
<Tooltip content={headerTitle} delayDuration={300}>
|
|
200
|
+
{headerWithType}
|
|
201
|
+
</Tooltip>
|
|
202
|
+
) : (
|
|
203
|
+
headerWithType
|
|
204
|
+
);
|
|
205
|
+
|
|
187
206
|
const dataTableColumnHeader = (
|
|
188
207
|
<DataTableColumnHeader
|
|
189
|
-
header={
|
|
208
|
+
header={headerWithTooltip}
|
|
190
209
|
column={column}
|
|
191
210
|
calculateTopKRows={calculateTopKRows}
|
|
192
211
|
/>
|
|
@@ -47,7 +47,8 @@ import { getStableRowId } from "./utils";
|
|
|
47
47
|
interface DataTableProps<TData> extends Partial<DownloadActionProps> {
|
|
48
48
|
wrapperClassName?: string;
|
|
49
49
|
className?: string;
|
|
50
|
-
|
|
50
|
+
maxHeight?: number;
|
|
51
|
+
columns: ColumnDef<TData>[];
|
|
51
52
|
data: TData[];
|
|
52
53
|
// Sorting
|
|
53
54
|
manualSorting?: boolean; // server-side sorting
|
|
@@ -95,6 +96,7 @@ interface DataTableProps<TData> extends Partial<DownloadActionProps> {
|
|
|
95
96
|
const DataTableInternal = <TData,>({
|
|
96
97
|
wrapperClassName,
|
|
97
98
|
className,
|
|
99
|
+
maxHeight,
|
|
98
100
|
columns,
|
|
99
101
|
data,
|
|
100
102
|
selection,
|
|
@@ -250,6 +252,36 @@ const DataTableInternal = <TData,>({
|
|
|
250
252
|
|
|
251
253
|
const rowViewerPanelOpen = isPanelOpen?.("row-viewer") ?? false;
|
|
252
254
|
|
|
255
|
+
const tableRef = React.useRef<HTMLTableElement | null>(null);
|
|
256
|
+
|
|
257
|
+
// Why use a ref to set max-height on the wrapper?
|
|
258
|
+
// - position: sticky only works when the sticky element's nearest scrollable
|
|
259
|
+
// ancestor is its immediate container. If max-height/overflow are applied
|
|
260
|
+
// on a grandparent, sticky table headers (th) will not stick.
|
|
261
|
+
// - We keep the scroll wrapper colocated with the base Table component, but
|
|
262
|
+
// derive the scroll boundary from maxHeight here to avoid coupling UI base
|
|
263
|
+
// components to data-table specifics or expanding their API surface.
|
|
264
|
+
// - Setting styles on the table's direct wrapper ensures the header sticks
|
|
265
|
+
// reliably across browsers without changing upstream components.
|
|
266
|
+
React.useEffect(() => {
|
|
267
|
+
if (!tableRef.current) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const wrapper = tableRef.current.parentElement as HTMLDivElement | null;
|
|
271
|
+
if (!wrapper) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (maxHeight) {
|
|
275
|
+
wrapper.style.maxHeight = `${maxHeight}px`;
|
|
276
|
+
// Ensure wrapper scrolls
|
|
277
|
+
if (!wrapper.style.overflow) {
|
|
278
|
+
wrapper.style.overflow = "auto";
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
wrapper.style.removeProperty("max-height");
|
|
282
|
+
}
|
|
283
|
+
}, [maxHeight]);
|
|
284
|
+
|
|
253
285
|
return (
|
|
254
286
|
<div className={cn(wrapperClassName, "flex flex-col space-y-1")}>
|
|
255
287
|
<FilterPills filters={filters} table={table} />
|
|
@@ -263,11 +295,11 @@ const DataTableInternal = <TData,>({
|
|
|
263
295
|
reloading={reloading}
|
|
264
296
|
/>
|
|
265
297
|
)}
|
|
266
|
-
<Table className="relative">
|
|
298
|
+
<Table className="relative" ref={tableRef}>
|
|
267
299
|
{showLoadingBar && (
|
|
268
300
|
<div className="absolute top-0 left-0 h-[3px] w-1/2 bg-primary animate-slide" />
|
|
269
301
|
)}
|
|
270
|
-
{renderTableHeader(table)}
|
|
302
|
+
{renderTableHeader(table, Boolean(maxHeight))}
|
|
271
303
|
<CellSelectionProvider>
|
|
272
304
|
<DataTableBody
|
|
273
305
|
table={table}
|
|
@@ -124,7 +124,7 @@ const RelativeTime = ({ date }: { date: Date }) => {
|
|
|
124
124
|
const differenceInSeconds = (currentTime.getTime() - date.getTime()) / 1000;
|
|
125
125
|
|
|
126
126
|
// Define time units with their thresholds and conversion factors
|
|
127
|
-
const timeUnits:
|
|
127
|
+
const timeUnits: [number, number, string][] = [
|
|
128
128
|
[60, 1, "second"], // Less than 60 seconds
|
|
129
129
|
[60, 60, "minute"], // Less than 60 minutes
|
|
130
130
|
[24, 3600, "hour"], // Less than 24 hours
|
|
@@ -167,7 +167,7 @@ export const DownloadAs: React.FC<DownloadActionProps> = (props) => {
|
|
|
167
167
|
);
|
|
168
168
|
};
|
|
169
169
|
|
|
170
|
-
function fetchJson(url: string): Promise<
|
|
170
|
+
function fetchJson(url: string): Promise<Record<string, unknown>[]> {
|
|
171
171
|
return fetch(url).then((res) => {
|
|
172
172
|
if (!res.ok) {
|
|
173
173
|
throw new Error(res.statusText);
|
|
@@ -20,17 +20,17 @@ function createMockCell(id: string, value: unknown): Cell<unknown, unknown> {
|
|
|
20
20
|
function createMockColumn(id: string): Column<unknown> {
|
|
21
21
|
return {
|
|
22
22
|
id: id,
|
|
23
|
-
getIndex: () => Number.parseInt(id),
|
|
23
|
+
getIndex: () => Number.parseInt(id, 10),
|
|
24
24
|
} as unknown as Column<unknown>;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function createMockRow(
|
|
28
28
|
id: string,
|
|
29
|
-
cells:
|
|
29
|
+
cells: Cell<unknown, unknown>[],
|
|
30
30
|
): Row<unknown> {
|
|
31
31
|
return {
|
|
32
32
|
id,
|
|
33
|
-
index: Number.parseInt(id),
|
|
33
|
+
index: Number.parseInt(id, 10),
|
|
34
34
|
getAllCells: () => cells,
|
|
35
35
|
original: {},
|
|
36
36
|
depth: 0,
|
|
@@ -43,8 +43,8 @@ function createMockRow(
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function createMockTable(
|
|
46
|
-
rows:
|
|
47
|
-
columns:
|
|
46
|
+
rows: Row<unknown>[],
|
|
47
|
+
columns: Column<unknown>[],
|
|
48
48
|
): Table<unknown> {
|
|
49
49
|
return {
|
|
50
50
|
getRow: (id: string) => rows.find((row) => row.id === id),
|
|
@@ -26,12 +26,13 @@ import { useScrollIntoViewOnFocus } from "./range-focus/use-scroll-into-view";
|
|
|
26
26
|
|
|
27
27
|
export function renderTableHeader<TData>(
|
|
28
28
|
table: Table<TData>,
|
|
29
|
+
isSticky?: boolean,
|
|
29
30
|
): JSX.Element | null {
|
|
30
31
|
if (!table.getRowModel().rows?.length) {
|
|
31
32
|
return null;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
const renderHeaderGroup = (headerGroups:
|
|
35
|
+
const renderHeaderGroup = (headerGroups: HeaderGroup<TData>[]) => {
|
|
35
36
|
return headerGroups.map((headerGroup) =>
|
|
36
37
|
headerGroup.headers.map((header) => {
|
|
37
38
|
const { className, style } = getPinningStyles(header.column);
|
|
@@ -57,7 +58,7 @@ export function renderTableHeader<TData>(
|
|
|
57
58
|
};
|
|
58
59
|
|
|
59
60
|
return (
|
|
60
|
-
<TableHeader>
|
|
61
|
+
<TableHeader className={cn(isSticky && "sticky top-0 z-10")}>
|
|
61
62
|
<TableRow>
|
|
62
63
|
{renderHeaderGroup(table.getLeftHeaderGroups())}
|
|
63
64
|
{renderHeaderGroup(table.getCenterHeaderGroups())}
|
|
@@ -69,7 +70,7 @@ export function renderTableHeader<TData>(
|
|
|
69
70
|
|
|
70
71
|
interface DataTableBodyProps<TData> {
|
|
71
72
|
table: Table<TData>;
|
|
72
|
-
columns:
|
|
73
|
+
columns: ColumnDef<TData>[];
|
|
73
74
|
rowViewerPanelOpen: boolean;
|
|
74
75
|
getRowIndex?: (row: TData, idx: number) => number;
|
|
75
76
|
viewedRowIdx?: number;
|
|
@@ -95,7 +96,7 @@ export const DataTableBody = <TData,>({
|
|
|
95
96
|
|
|
96
97
|
function applyHoverTemplate(
|
|
97
98
|
template: string,
|
|
98
|
-
cells:
|
|
99
|
+
cells: Cell<TData, unknown>[],
|
|
99
100
|
): string {
|
|
100
101
|
const variableRegex = /{{(\w+)}}/g;
|
|
101
102
|
// Map column id -> stringified value
|
|
@@ -106,13 +107,13 @@ export const DataTableBody = <TData,>({
|
|
|
106
107
|
const s = renderUnknownValue({ value: v, nullAsEmptyString: true });
|
|
107
108
|
idToValue.set(c.column.id, s);
|
|
108
109
|
}
|
|
109
|
-
return template.
|
|
110
|
+
return template.replaceAll(variableRegex, (_substr, varName: string) => {
|
|
110
111
|
const val = idToValue.get(varName);
|
|
111
|
-
return val
|
|
112
|
+
return val === undefined ? `{{${varName}}}` : val;
|
|
112
113
|
});
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
const renderCells = (cells:
|
|
116
|
+
const renderCells = (cells: Cell<TData, unknown>[]) => {
|
|
116
117
|
return cells.map((cell) => {
|
|
117
118
|
const { className, style: pinningstyle } = getPinningStyles(cell.column);
|
|
118
119
|
const style = Object.assign(
|
|
@@ -154,6 +155,8 @@ export const DataTableBody = <TData,>({
|
|
|
154
155
|
}
|
|
155
156
|
};
|
|
156
157
|
|
|
158
|
+
const hoverTemplate = table.getState().cellHoverTemplate || null;
|
|
159
|
+
|
|
157
160
|
return (
|
|
158
161
|
<TableBody onKeyDown={handleCellsKeyDown} ref={tableRef}>
|
|
159
162
|
{table.getRowModel().rows?.length ? (
|
|
@@ -165,12 +168,18 @@ export const DataTableBody = <TData,>({
|
|
|
165
168
|
const isRowViewedInPanel =
|
|
166
169
|
rowViewerPanelOpen && viewedRowIdx === rowIndex;
|
|
167
170
|
|
|
168
|
-
// Compute hover title once per row using
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
// Compute hover title once per row using all visible cells
|
|
172
|
+
let rowTitle: string | undefined;
|
|
173
|
+
if (hoverTemplate) {
|
|
174
|
+
const visibleCells = row.getVisibleCells?.() ?? [
|
|
175
|
+
...row.getLeftVisibleCells(),
|
|
176
|
+
...row.getCenterVisibleCells(),
|
|
177
|
+
...row.getRightVisibleCells(),
|
|
178
|
+
];
|
|
179
|
+
rowTitle = hoverTemplate
|
|
180
|
+
? applyHoverTemplate(hoverTemplate, visibleCells)
|
|
181
|
+
: undefined;
|
|
182
|
+
}
|
|
174
183
|
|
|
175
184
|
return (
|
|
176
185
|
<TableRow
|
|
@@ -188,7 +188,7 @@ export const RowViewerPanel: React.FC<RowViewerPanelProps> = ({
|
|
|
188
188
|
</TableRow>
|
|
189
189
|
</TableHeader>
|
|
190
190
|
<TableBody>
|
|
191
|
-
{fieldTypes?.map(([columnName, [dataType,
|
|
191
|
+
{fieldTypes?.map(([columnName, [dataType, _externalType]]) => {
|
|
192
192
|
const columnValue = rowValues[columnName];
|
|
193
193
|
|
|
194
194
|
if (!inSearchQuery({ columnName, columnValue, searchQuery })) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import z from "zod";
|
|
4
|
+
import { rpc } from "@/plugins/core/rpc";
|
|
5
|
+
|
|
6
|
+
export type DownloadAsArgs = (req: {
|
|
7
|
+
format: "csv" | "json" | "parquet";
|
|
8
|
+
}) => Promise<string>;
|
|
9
|
+
|
|
10
|
+
export const DownloadAsSchema = rpc
|
|
11
|
+
.input(
|
|
12
|
+
z.object({
|
|
13
|
+
format: z.enum(["csv", "json", "parquet"]),
|
|
14
|
+
}),
|
|
15
|
+
)
|
|
16
|
+
.output(z.string());
|
|
@@ -27,9 +27,10 @@ export type ColumnHeaderStats = Record<
|
|
|
27
27
|
number | string | null
|
|
28
28
|
>;
|
|
29
29
|
|
|
30
|
-
export type FieldTypesWithExternalType =
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
export type FieldTypesWithExternalType = [
|
|
31
|
+
columnName: string,
|
|
32
|
+
[dataType: DataType, externalType: string],
|
|
33
|
+
][];
|
|
33
34
|
export type FieldTypes = Record<string, DataType>;
|
|
34
35
|
|
|
35
36
|
export function toFieldTypes(
|
|
@@ -110,7 +110,8 @@ export const DatasetColumnPreview: React.FC<{
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
const stats =
|
|
113
|
-
preview.stats &&
|
|
113
|
+
preview.stats &&
|
|
114
|
+
renderStats({ stats: preview.stats, dataType: column.type, locale });
|
|
114
115
|
|
|
115
116
|
const chart = preview.chart_spec && renderChart(preview.chart_spec, theme);
|
|
116
117
|
|
|
@@ -175,11 +176,13 @@ export function renderPreviewError({
|
|
|
175
176
|
);
|
|
176
177
|
}
|
|
177
178
|
|
|
178
|
-
|
|
179
|
-
stats: Partial<Record<ColumnHeaderStatsKey, unknown
|
|
180
|
-
dataType: DataType
|
|
181
|
-
locale: string
|
|
182
|
-
|
|
179
|
+
interface RenderStatsProps {
|
|
180
|
+
stats: Partial<Record<ColumnHeaderStatsKey, unknown>>;
|
|
181
|
+
dataType: DataType;
|
|
182
|
+
locale: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function renderStats({ stats, dataType, locale }: RenderStatsProps) {
|
|
183
186
|
return (
|
|
184
187
|
<div className="gap-x-16 gap-y-1 grid grid-cols-2-fit border rounded p-2 empty:hidden">
|
|
185
188
|
{Object.entries(stats).map(([key, value]) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Copyright 2024 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { useAtomValue } from "jotai";
|
|
4
|
-
import React, { memo, use } from "react";
|
|
4
|
+
import React, { memo, use, useId } from "react";
|
|
5
5
|
import { Handle, Position, useStore } from "reactflow";
|
|
6
6
|
import { TinyCode } from "@/components/editor/cell/TinyCode";
|
|
7
7
|
import { useCellIds } from "@/core/cells/cells";
|
|
@@ -23,7 +23,7 @@ const EQUALITY_CHECK = (
|
|
|
23
23
|
prevProps: CustomNodeProps,
|
|
24
24
|
nextProps: CustomNodeProps,
|
|
25
25
|
) => {
|
|
26
|
-
const keys:
|
|
26
|
+
const keys: (keyof CustomNodeProps)[] = ["data", "selected", "id"];
|
|
27
27
|
return keys.every((key) => prevProps[key] === nextProps[key]);
|
|
28
28
|
};
|
|
29
29
|
|
|
@@ -37,18 +37,25 @@ export const CustomNode = memo((props: CustomNodeProps) => {
|
|
|
37
37
|
const reactFlowWidth = useStore(({ width }) => width);
|
|
38
38
|
const edgeMarkers = use(EdgeMarkerContext);
|
|
39
39
|
|
|
40
|
+
const inputOneId = useId();
|
|
41
|
+
const inputTwoId = useId();
|
|
42
|
+
const outputOneId = useId();
|
|
43
|
+
const outputTwoId = useId();
|
|
44
|
+
|
|
40
45
|
const linesOfCode = cell.code.split("\n").length;
|
|
41
46
|
return (
|
|
42
47
|
<div>
|
|
43
48
|
<Handle
|
|
44
49
|
type="target"
|
|
45
|
-
id=
|
|
50
|
+
id={inputOneId}
|
|
51
|
+
data-testid="input-one"
|
|
46
52
|
position={edgeMarkers === "LR" ? Position.Left : Position.Top}
|
|
47
53
|
style={{ background: color }}
|
|
48
54
|
/>
|
|
49
55
|
<Handle
|
|
50
56
|
type="source"
|
|
51
|
-
id=
|
|
57
|
+
id={inputTwoId}
|
|
58
|
+
data-testid="input-two"
|
|
52
59
|
position={edgeMarkers === "LR" ? Position.Left : Position.Top}
|
|
53
60
|
style={{ background: color }}
|
|
54
61
|
/>
|
|
@@ -69,13 +76,15 @@ export const CustomNode = memo((props: CustomNodeProps) => {
|
|
|
69
76
|
</div>
|
|
70
77
|
<Handle
|
|
71
78
|
type="source"
|
|
72
|
-
id=
|
|
79
|
+
id={outputOneId}
|
|
80
|
+
data-testid="output-one"
|
|
73
81
|
position={edgeMarkers === "LR" ? Position.Right : Position.Bottom}
|
|
74
82
|
style={{ background: color }}
|
|
75
83
|
/>
|
|
76
84
|
<Handle
|
|
77
85
|
type="target"
|
|
78
|
-
id=
|
|
86
|
+
id={outputTwoId}
|
|
87
|
+
data-testid="output-two"
|
|
79
88
|
position={edgeMarkers === "LR" ? Position.Right : Position.Bottom}
|
|
80
89
|
style={{ background: color }}
|
|
81
90
|
/>
|
|
@@ -31,7 +31,7 @@ import { useFitToViewOnDimensionChange } from "./utils/useFitToViewOnDimensionCh
|
|
|
31
31
|
interface Props {
|
|
32
32
|
cellIds: CellId[];
|
|
33
33
|
variables: Variables;
|
|
34
|
-
cellAtoms:
|
|
34
|
+
cellAtoms: Atom<CellData>[];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const elementsBuilder = new VerticalElementsBuilder();
|
|
@@ -57,7 +57,7 @@ export const DependencyGraphMinimap: React.FC<PropsWithChildren<Props>> = ({
|
|
|
57
57
|
|
|
58
58
|
// If the cellIds change, update the nodes.
|
|
59
59
|
const syncChanges = useEvent(
|
|
60
|
-
(elements: { nodes:
|
|
60
|
+
(elements: { nodes: Node<NodeData>[]; edges: Edge[] }) => {
|
|
61
61
|
setNodes(elements.nodes);
|
|
62
62
|
setEdges([]);
|
|
63
63
|
},
|
|
@@ -36,7 +36,7 @@ import { useFitToViewOnDimensionChange } from "./utils/useFitToViewOnDimensionCh
|
|
|
36
36
|
interface Props {
|
|
37
37
|
cellIds: CellId[];
|
|
38
38
|
variables: Variables;
|
|
39
|
-
cellAtoms:
|
|
39
|
+
cellAtoms: Atom<CellData>[];
|
|
40
40
|
layoutDirection: LayoutDirection;
|
|
41
41
|
settings: GraphSettings;
|
|
42
42
|
}
|
|
@@ -74,7 +74,7 @@ export const DependencyGraphTree: React.FC<PropsWithChildren<Props>> = ({
|
|
|
74
74
|
const api = useReactFlow();
|
|
75
75
|
|
|
76
76
|
const syncChanges = useEvent(
|
|
77
|
-
(elements: { nodes:
|
|
77
|
+
(elements: { nodes: Node<NodeData>[]; edges: Edge[] }) => {
|
|
78
78
|
// Layout the elements
|
|
79
79
|
const result = layoutElements({
|
|
80
80
|
nodes: elements.nodes,
|
|
@@ -22,10 +22,10 @@ export function getNodeHeight(linesOfCode: number) {
|
|
|
22
22
|
interface ElementsBuilder {
|
|
23
23
|
createElements: (
|
|
24
24
|
cellIds: CellId[],
|
|
25
|
-
cellAtoms:
|
|
25
|
+
cellAtoms: Atom<CellData>[],
|
|
26
26
|
variables: Variables,
|
|
27
27
|
hidePureMarkdown: boolean,
|
|
28
|
-
) => { nodes:
|
|
28
|
+
) => { nodes: Node<NodeData>[]; edges: Edge[] };
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export class VerticalElementsBuilder implements ElementsBuilder {
|
|
@@ -69,12 +69,12 @@ export class VerticalElementsBuilder implements ElementsBuilder {
|
|
|
69
69
|
|
|
70
70
|
createElements(
|
|
71
71
|
cellIds: CellId[],
|
|
72
|
-
cellAtoms:
|
|
72
|
+
cellAtoms: Atom<CellData>[],
|
|
73
73
|
variables: Variables,
|
|
74
|
-
|
|
74
|
+
_hidePureMarkdown: boolean,
|
|
75
75
|
) {
|
|
76
76
|
let prevY = 0;
|
|
77
|
-
const nodes:
|
|
77
|
+
const nodes: Node<NodeData>[] = [];
|
|
78
78
|
const edges: Edge[] = [];
|
|
79
79
|
for (const [cellId, cellAtom] of Arrays.zip(cellIds, cellAtoms)) {
|
|
80
80
|
const node = this.createNode(cellId, cellAtom, prevY);
|
|
@@ -135,11 +135,11 @@ export class TreeElementsBuilder implements ElementsBuilder {
|
|
|
135
135
|
|
|
136
136
|
createElements(
|
|
137
137
|
cellIds: CellId[],
|
|
138
|
-
cellAtoms:
|
|
138
|
+
cellAtoms: Atom<CellData>[],
|
|
139
139
|
variables: Variables,
|
|
140
140
|
hidePureMarkdown: boolean,
|
|
141
141
|
) {
|
|
142
|
-
const nodes:
|
|
142
|
+
const nodes: Node<NodeData>[] = [];
|
|
143
143
|
const edges: Edge[] = [];
|
|
144
144
|
|
|
145
145
|
const nodesWithEdges = new Set<CellId>();
|
|
@@ -11,8 +11,8 @@ import type {
|
|
|
11
11
|
export function getNodeChanges(
|
|
12
12
|
prevNodes: Node[],
|
|
13
13
|
nextNodes: Node[],
|
|
14
|
-
):
|
|
15
|
-
const changes:
|
|
14
|
+
): (NodeAddChange | NodeRemoveChange)[] {
|
|
15
|
+
const changes: (NodeAddChange | NodeRemoveChange)[] = [];
|
|
16
16
|
const prevNodeIds = new Set(prevNodes.map((node) => node.id));
|
|
17
17
|
const nextNodeIds = new Set(nextNodes.map((node) => node.id));
|
|
18
18
|
|
|
@@ -33,8 +33,8 @@ export function getNodeChanges(
|
|
|
33
33
|
export function getEdgeChanges(
|
|
34
34
|
prevEdges: Edge[],
|
|
35
35
|
nextEdges: Edge[],
|
|
36
|
-
):
|
|
37
|
-
const changes:
|
|
36
|
+
): (EdgeAddChange | EdgeRemoveChange)[] {
|
|
37
|
+
const changes: (EdgeAddChange | EdgeRemoveChange)[] = [];
|
|
38
38
|
const prevEdgeIds = new Set(prevEdges.map((edge) => edge.id));
|
|
39
39
|
const nextEdgeIds = new Set(nextEdges.map((edge) => edge.id));
|
|
40
40
|
|
|
@@ -80,6 +80,7 @@ import { useDeleteCellCallback } from "./cell/useDeleteCell";
|
|
|
80
80
|
import { useRunCell } from "./cell/useRunCells";
|
|
81
81
|
import { HideCodeButton } from "./code/readonly-python-code";
|
|
82
82
|
import { cellDomProps } from "./common";
|
|
83
|
+
import { SqlValidationErrorBanner } from "./errors/sql-validation-errors";
|
|
83
84
|
import { useCellNavigationProps } from "./navigation/navigation";
|
|
84
85
|
import {
|
|
85
86
|
useTemporarilyShownCode,
|
|
@@ -450,6 +451,7 @@ const EditableCellComponent = ({
|
|
|
450
451
|
});
|
|
451
452
|
const canCollapse = canCollapseOutline(cellRuntime.outline);
|
|
452
453
|
const hasOutput = !isOutputEmpty(cellRuntime.output);
|
|
454
|
+
const isStaleCell = outputIsStale(cellRuntime, cellData.edited);
|
|
453
455
|
const hasConsoleOutput = cellRuntime.consoleOutputs.length > 0;
|
|
454
456
|
const cellOutput = userConfig.display.cell_output;
|
|
455
457
|
|
|
@@ -510,7 +512,7 @@ const EditableCellComponent = ({
|
|
|
510
512
|
className="output-area"
|
|
511
513
|
cellId={cellId}
|
|
512
514
|
output={cellRuntime.output}
|
|
513
|
-
stale={
|
|
515
|
+
stale={isStaleCell}
|
|
514
516
|
loading={outputIsLoading(cellRuntime.status)}
|
|
515
517
|
/>
|
|
516
518
|
{isMarkdownCodeHidden &&
|
|
@@ -653,6 +655,10 @@ const EditableCellComponent = ({
|
|
|
653
655
|
)}
|
|
654
656
|
</div>
|
|
655
657
|
</div>
|
|
658
|
+
<SqlValidationErrorBanner
|
|
659
|
+
cellId={cellId}
|
|
660
|
+
hide={cellRuntime.errored && !isStaleCell}
|
|
661
|
+
/>
|
|
656
662
|
{cellOutput === "below" && outputArea}
|
|
657
663
|
{cellRuntime.serialization && (
|
|
658
664
|
<div className="py-1 px-2 flex items-center justify-end gap-2 last:rounded-b">
|
|
@@ -16,7 +16,7 @@ export class StreamingChunkTransport<
|
|
|
16
16
|
private onChunkReceived: (chunk: UIMessageChunk) => void;
|
|
17
17
|
|
|
18
18
|
constructor(
|
|
19
|
-
options: HttpChatTransportInitOptions<UI_MESSAGE
|
|
19
|
+
options: HttpChatTransportInitOptions<UI_MESSAGE>,
|
|
20
20
|
onChunkReceived: (chunk: UIMessageChunk) => void,
|
|
21
21
|
) {
|
|
22
22
|
super(options);
|
|
@@ -18,7 +18,7 @@ function getRootScrollableElement() {
|
|
|
18
18
|
* React hook to find the active header in the outline
|
|
19
19
|
*/
|
|
20
20
|
export function useActiveOutline(
|
|
21
|
-
headerElements:
|
|
21
|
+
headerElements: (readonly [HTMLElement, string])[],
|
|
22
22
|
) {
|
|
23
23
|
const [activeHeaderId, setActiveHeaderId] = useState<string | undefined>(
|
|
24
24
|
undefined,
|
|
@@ -300,7 +300,7 @@ const InstallPackageForm: React.FC<{
|
|
|
300
300
|
|
|
301
301
|
const PackagesList: React.FC<{
|
|
302
302
|
onSuccess: () => void;
|
|
303
|
-
packages:
|
|
303
|
+
packages: { name: string; version: string }[];
|
|
304
304
|
}> = ({ onSuccess, packages }) => {
|
|
305
305
|
if (packages.length === 0) {
|
|
306
306
|
return (
|
|
@@ -7,7 +7,7 @@ import { NotebookScopedLocalStorage } from "@/utils/localStorage";
|
|
|
7
7
|
const BASE_KEY = "marimo:notebook-col-sizes";
|
|
8
8
|
|
|
9
9
|
interface ColumnSizes {
|
|
10
|
-
widths:
|
|
10
|
+
widths: (number | "contentWidth")[];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function initialState(): ColumnSizes {
|
|
@@ -28,6 +28,42 @@ engine = clickhouse_connect.get_client(
|
|
|
28
28
|
)"
|
|
29
29
|
`;
|
|
30
30
|
|
|
31
|
+
exports[`generateDatabaseCode > basic connections > databricks 1`] = `
|
|
32
|
+
"import os
|
|
33
|
+
import sqlalchemy
|
|
34
|
+
|
|
35
|
+
_access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
|
|
36
|
+
_server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
|
|
37
|
+
_http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
|
|
38
|
+
DATABASE_URL = f"databricks://token:{_access_token}@{_server_hostname}?http_path={_http_path}"
|
|
39
|
+
engine = sqlalchemy.create_engine(DATABASE_URL)"
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
exports[`generateDatabaseCode > basic connections > databricks with catalog and schema 1`] = `
|
|
43
|
+
"import os
|
|
44
|
+
import sqlalchemy
|
|
45
|
+
|
|
46
|
+
_access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
|
|
47
|
+
_server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
|
|
48
|
+
_http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
|
|
49
|
+
DATABASE_URL = f"databricks://token:{_access_token}@{_server_hostname}?http_path={_http_path}&catalog=my_catalog&schema=my_schema"
|
|
50
|
+
engine = sqlalchemy.create_engine(DATABASE_URL)"
|
|
51
|
+
`;
|
|
52
|
+
|
|
53
|
+
exports[`generateDatabaseCode > basic connections > databricks with ibis 1`] = `
|
|
54
|
+
"import ibis
|
|
55
|
+
import os
|
|
56
|
+
|
|
57
|
+
_access_token = os.environ.get("DATABRICKS_ACCESS_TOKEN", "my_access_token")
|
|
58
|
+
_server_hostname = os.environ.get("DATABRICKS_SERVER_HOSTNAME", "localhost")
|
|
59
|
+
_http_path = os.environ.get("DATABRICKS_HTTP_PATH", "http://localhost:8080")
|
|
60
|
+
engine = ibis.databricks.connect(
|
|
61
|
+
server_hostname=_server_hostname,
|
|
62
|
+
http_path=_http_path,
|
|
63
|
+
access_token=_access_token
|
|
64
|
+
)"
|
|
65
|
+
`;
|
|
66
|
+
|
|
31
67
|
exports[`generateDatabaseCode > basic connections > datafusion 1`] = `
|
|
32
68
|
"from datafusion import SessionContext
|
|
33
69
|
import ibis
|