@marimo-team/frontend 0.22.5-dev9 → 0.22.5

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.
Files changed (102) hide show
  1. package/dist/assets/{CellStatus-vLQ0PRhL.js → CellStatus-CNNGwOIK.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-CAllw3YA.js → ConnectedDataExplorerComponent-CfU-ThkK.js} +1 -1
  3. package/dist/assets/JsonOutput-9XtRRx5l.js +49 -0
  4. package/dist/assets/{MarimoErrorOutput-CbOtWgTE.js → MarimoErrorOutput-Bc9JufDr.js} +2 -2
  5. package/dist/assets/{RenderHTML-HmYLAtrW.js → RenderHTML-0dk6-mYI.js} +1 -1
  6. package/dist/assets/{add-cell-with-ai-DVz3Rqa3.js → add-cell-with-ai-CLklC7KS.js} +8 -8
  7. package/dist/assets/{add-connection-dialog-Bu5E77IS.js → add-connection-dialog-ux7eCDRM.js} +1 -1
  8. package/dist/assets/{agent-panel-HMju_soU.js → agent-panel-CiMrqUfl.js} +3 -3
  9. package/dist/assets/{ai-model-dropdown-DUK_vWZh.js → ai-model-dropdown-CRtaHcCu.js} +3 -3
  10. package/dist/assets/{app-config-button-CVraCieA.js → app-config-button-CnX21edo.js} +1 -1
  11. package/dist/assets/{cache-panel-5QBCQUqv.js → cache-panel-8E_Y5OSb.js} +1 -1
  12. package/dist/assets/{cell-editor-CEok7I_G.js → cell-editor-D7IQ3F4W.js} +10 -10
  13. package/dist/assets/{cell-link-D5GhiNrn.js → cell-link-CcAqXeeg.js} +1 -1
  14. package/dist/assets/{cells-CuaAKcwV.js → cells-EJo3u4za.js} +43 -43
  15. package/dist/assets/{chat-display-ktpBhrn7.js → chat-display-BxDRpNsl.js} +1 -1
  16. package/dist/assets/{chat-panel-BzN2cf87.js → chat-panel-dBoLqgjH.js} +1 -1
  17. package/dist/assets/{chat-ui-Da4qjTuA.js → chat-ui-DdZo1L-v.js} +1 -1
  18. package/dist/assets/{column-preview-BLzfoQuq.js → column-preview-DrU255Z3.js} +1 -1
  19. package/dist/assets/{command-palette-DNvYHUpi.js → command-palette-n6NnK6GP.js} +1 -1
  20. package/dist/assets/{common-BKyn8lE1.js → common-Bty2yo-n.js} +1 -1
  21. package/dist/assets/{components-CtOW1DR4.js → components-B8TZ_vT_.js} +1 -1
  22. package/dist/assets/{components-CBihADZo.js → components-Dh-L-jYg.js} +1 -1
  23. package/dist/assets/config-DoZCLcOb.js +1 -0
  24. package/dist/assets/{datasource-DwmhT5-D.js → datasource-DY0N42ZB.js} +1 -1
  25. package/dist/assets/{dependency-graph-panel-Cq1gKP3a.js → dependency-graph-panel-C23HsAdh.js} +1 -1
  26. package/dist/assets/{documentation-panel-Dd6ys__C.js → documentation-panel-okcEKCQM.js} +1 -1
  27. package/dist/assets/{download-CxGVI9eo.js → download-TSo32ofd.js} +3 -3
  28. package/dist/assets/{edit-page-DJprVtJ6.js → edit-page-RhmoqI7E.js} +7 -7
  29. package/dist/assets/{error-panel-BiGfbiiW.js → error-panel-aq2j0jIa.js} +1 -1
  30. package/dist/assets/{file-explorer-panel-DiNhLdAc.js → file-explorer-panel-CzYUz358.js} +1 -1
  31. package/dist/assets/{file-icons-DaGma7HH.js → file-icons-DBaXCICA.js} +1 -1
  32. package/dist/assets/{floating-outline-oPCmn9_F.js → floating-outline-BTmyhMGv.js} +1 -1
  33. package/dist/assets/{focus-B524Cy57.js → focus-DXeddo75.js} +1 -1
  34. package/dist/assets/{form-BV-yji2Y.js → form-BiDLPu7R.js} +1 -1
  35. package/dist/assets/{gallery-page-CI72Q71Y.js → gallery-page-XSrY7bw_.js} +1 -1
  36. package/dist/assets/{globals-Bh85lAn7.js → globals-DQM2RvzM.js} +1 -1
  37. package/dist/assets/{home-page-kYSYG7Zh.js → home-page-BntiR5eS.js} +2 -2
  38. package/dist/assets/{hooks-SmuOPKfj.js → hooks-BgwM3Mb2.js} +1 -1
  39. package/dist/assets/{html-to-image-C-c-Hfuw.js → html-to-image-BJiJlwQY.js} +1 -1
  40. package/dist/assets/index-CMEhtk8a.js +42 -0
  41. package/dist/assets/index-DBs2il8a.css +2 -0
  42. package/dist/assets/{kiosk-mode-CnJjuo6B.js → kiosk-mode-JCcLyeoQ.js} +1 -1
  43. package/dist/assets/{layout-BxUONa-J.js → layout-CF-7BNtf.js} +3 -3
  44. package/dist/assets/{logs-panel-BH5Q_Nct.js → logs-panel-BzhPrie8.js} +1 -1
  45. package/dist/assets/{markdown-renderer-2XpTunxF.js → markdown-renderer-B9RsGqHb.js} +1 -1
  46. package/dist/assets/{mermaid-KL-Hgqp7.js → mermaid-BJFSZcG6.js} +1 -1
  47. package/dist/assets/{name-cell-input-CIZAWlBG.js → name-cell-input-CYsY4A1G.js} +1 -1
  48. package/dist/assets/{outline-panel-BXefyCJ4.js → outline-panel-BCAWCKi6.js} +1 -1
  49. package/dist/assets/{packages-panel-De0Fg43N.js → packages-panel-5axf3DuF.js} +1 -1
  50. package/dist/assets/{panels-DuR2pNy9.js → panels-7-kbDRzv.js} +1 -1
  51. package/dist/assets/{process-output-C-VBRULx.js → process-output-DqiZsqG9.js} +1 -1
  52. package/dist/assets/{readonly-python-code-BhME4c6A.js → readonly-python-code-D8ITm60r.js} +1 -1
  53. package/dist/assets/{run-page-BDV1C8Oi.js → run-page-9OQqe8IY.js} +1 -1
  54. package/dist/assets/{scratchpad-panel-CWU7CyZh.js → scratchpad-panel-DkqxnSH6.js} +1 -1
  55. package/dist/assets/{secrets-panel-CyJ4KdCC.js → secrets-panel-C6X5jB8Q.js} +1 -1
  56. package/dist/assets/{session-panel-B8t0Xymv.js → session-panel-BuzMiMf3.js} +1 -1
  57. package/dist/assets/{snippets-panel-BaV08Ib1.js → snippets-panel--mh2FUXA.js} +1 -1
  58. package/dist/assets/{state-WTTs5oP6.js → state-6D_2UAw3.js} +2 -2
  59. package/dist/assets/{state-DuVk71Dw.js → state-BDrig0S2.js} +1 -1
  60. package/dist/assets/{state-9-n7I_Bo.js → state-BgrGQPFs.js} +1 -1
  61. package/dist/assets/{switch-C2idsSNO.js → switch-C6xjg01T.js} +1 -1
  62. package/dist/assets/{terminal-BBTjIXBz.js → terminal-BEaHyVIQ.js} +1 -1
  63. package/dist/assets/{textarea-CI3yaazO.js → textarea-Cfp3upzK.js} +1 -1
  64. package/dist/assets/{tracing-ChWqFQa-.js → tracing-BExYhl1z.js} +1 -1
  65. package/dist/assets/{tracing-panel-B46P3LAM.js → tracing-panel-Co5DeX-F.js} +2 -2
  66. package/dist/assets/{useAddCell-BMYemCZ-.js → useAddCell-BaTlDxTu.js} +1 -1
  67. package/dist/assets/{useAsyncData-CaAFMbY9.js → useAsyncData-aCoWDe-l.js} +1 -1
  68. package/dist/assets/{useBoolean-ugd5JdXd.js → useBoolean-BvsK1Xcs.js} +1 -1
  69. package/dist/assets/{useCellActionButton-BKZyr81R.js → useCellActionButton-DftkIqUl.js} +1 -1
  70. package/dist/assets/{useDeleteCell-6SLN_jZa.js → useDeleteCell-d6yWnL3H.js} +1 -1
  71. package/dist/assets/{useDependencyPanelTab-JOuBqQ1y.js → useDependencyPanelTab-BaVcOBM4.js} +1 -1
  72. package/dist/assets/{useNotebookActions-D2fp_HNm.js → useNotebookActions-DihtSJ4g.js} +1 -1
  73. package/dist/assets/{useRunCells-B5o8P7HV.js → useRunCells-d2edY6Tu.js} +1 -1
  74. package/dist/assets/{useSplitCell-Dn4N4Evl.js → useSplitCell-DOiFyMgH.js} +1 -1
  75. package/dist/assets/{vega-component-D_AgSSfE.js → vega-component-CiVPyAwP.js} +1 -1
  76. package/dist/index.html +29 -28
  77. package/package.json +2 -2
  78. package/src/components/data-table/__tests__/columns.test.tsx +92 -13
  79. package/src/components/data-table/column-header.tsx +81 -56
  80. package/src/components/data-table/columns.tsx +25 -32
  81. package/src/components/data-table/data-table.tsx +8 -1
  82. package/src/components/data-table/renderers.tsx +19 -6
  83. package/src/components/data-table/types.ts +4 -0
  84. package/src/components/editor/Output.tsx +1 -1
  85. package/src/components/editor/__tests__/Output.test.tsx +36 -1
  86. package/src/core/cells/__tests__/cells.test.ts +41 -0
  87. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +38 -0
  88. package/src/core/cells/cells.ts +1 -1
  89. package/src/core/cells/collapseConsoleOutputs.tsx +3 -0
  90. package/src/core/cells/document-changes.ts +12 -0
  91. package/src/core/runtime/__tests__/runtime.test.ts +138 -2
  92. package/src/core/runtime/runtime.ts +25 -5
  93. package/src/core/saving/file-state.ts +16 -0
  94. package/src/hooks/useAsyncData.ts +1 -1
  95. package/src/mount.tsx +17 -1
  96. package/src/plugins/impl/DataTablePlugin.tsx +1 -1
  97. package/src/plugins/impl/plotly/__tests__/selection.test.ts +22 -0
  98. package/src/plugins/impl/plotly/selection.ts +1 -0
  99. package/dist/assets/JsonOutput-Dl2dfhmz.js +0 -49
  100. package/dist/assets/config-Cgj0Ahvb.js +0 -1
  101. package/dist/assets/index-BNN_F0CC.css +0 -2
  102. package/dist/assets/index-By2ge4IZ.js +0 -42
@@ -86,6 +86,74 @@ describe("RuntimeManager", () => {
86
86
  });
87
87
  });
88
88
 
89
+ describe("cross-origin auth token in WS URLs", () => {
90
+ it("should add access_token to WS URL when cross-origin with authToken", () => {
91
+ // example.com is cross-origin relative to the test environment (localhost)
92
+ const runtime = new RuntimeManager(
93
+ {
94
+ url: "https://sandbox.example.com",
95
+ lazy: true,
96
+ authToken: "my-secret-token",
97
+ },
98
+ true,
99
+ );
100
+ const url = runtime.getWsURL("s_123" as SessionId);
101
+
102
+ expect(url.searchParams.get("access_token")).toBe("my-secret-token");
103
+ expect(url.searchParams.get("session_id")).toBe("s_123");
104
+ });
105
+
106
+ it("should not add access_token to WS URL when same-origin", () => {
107
+ const runtime = new RuntimeManager(
108
+ {
109
+ url: window.location.origin,
110
+ lazy: true,
111
+ authToken: "my-secret-token",
112
+ },
113
+ true,
114
+ );
115
+ const url = runtime.getWsURL("s_123" as SessionId);
116
+
117
+ expect(url.searchParams.get("access_token")).toBeNull();
118
+ });
119
+
120
+ it("should not add access_token when no authToken is configured", () => {
121
+ const runtime = new RuntimeManager(
122
+ {
123
+ url: "https://sandbox.example.com",
124
+ lazy: true,
125
+ },
126
+ true,
127
+ );
128
+ const url = runtime.getWsURL("s_123" as SessionId);
129
+
130
+ expect(url.searchParams.get("access_token")).toBeNull();
131
+ });
132
+
133
+ it("should add access_token to all WS URL types when cross-origin", () => {
134
+ const runtime = new RuntimeManager(
135
+ {
136
+ url: "https://sandbox.example.com",
137
+ lazy: true,
138
+ authToken: "my-secret-token",
139
+ },
140
+ true,
141
+ );
142
+
143
+ const wsUrl = runtime.getWsURL("s_123" as SessionId);
144
+ const wsSyncUrl = runtime.getWsSyncURL("s_123" as SessionId);
145
+ const terminalUrl = runtime.getTerminalWsURL();
146
+
147
+ expect(wsUrl.searchParams.get("access_token")).toBe("my-secret-token");
148
+ expect(wsSyncUrl.searchParams.get("access_token")).toBe(
149
+ "my-secret-token",
150
+ );
151
+ expect(terminalUrl.searchParams.get("access_token")).toBe(
152
+ "my-secret-token",
153
+ );
154
+ });
155
+ });
156
+
89
157
  describe("getWsSyncURL", () => {
90
158
  it("should return WebSocket Sync URL", () => {
91
159
  const runtime = new RuntimeManager(mockConfig);
@@ -117,12 +185,52 @@ describe("RuntimeManager", () => {
117
185
  expect(url.pathname).toBe("/lsp/pylsp");
118
186
  });
119
187
 
120
- it("should return copilot URL", () => {
121
- const runtime = new RuntimeManager(mockConfig);
188
+ it("should return copilot URL without non-auth query params", () => {
189
+ const runtime = new RuntimeManager({
190
+ url: "https://example.com?foo=bar&baz=qux",
191
+ lazy: true,
192
+ });
122
193
  const url = runtime.getLSPURL("copilot");
123
194
 
124
195
  expect(url.protocol).toBe("wss:");
125
196
  expect(url.pathname).toBe("/lsp/copilot");
197
+ expect(url.searchParams.get("foo")).toBeNull();
198
+ expect(url.searchParams.get("baz")).toBeNull();
199
+ });
200
+
201
+ it("should preserve access_token on copilot URL when cross-origin", () => {
202
+ const runtime = new RuntimeManager(
203
+ {
204
+ url: "https://sandbox.example.com?foo=bar",
205
+ lazy: true,
206
+ authToken: "my-secret-token",
207
+ },
208
+ true,
209
+ );
210
+ const url = runtime.getLSPURL("copilot");
211
+
212
+ expect(url.protocol).toBe("wss:");
213
+ expect(url.pathname).toBe("/lsp/copilot");
214
+ expect(url.searchParams.get("access_token")).toBe("my-secret-token");
215
+ // Other params should be stripped
216
+ expect(url.searchParams.get("foo")).toBeNull();
217
+ });
218
+
219
+ it("should not have access_token on copilot URL when same-origin", () => {
220
+ const runtime = new RuntimeManager(
221
+ {
222
+ url: window.location.origin,
223
+ lazy: true,
224
+ authToken: "my-secret-token",
225
+ },
226
+ true,
227
+ );
228
+ const url = runtime.getLSPURL("copilot");
229
+
230
+ expect(url.protocol).toBe("ws:");
231
+ expect(url.pathname).toBe("/lsp/copilot");
232
+ expect(url.searchParams.get("access_token")).toBeNull();
233
+ expect(url.search).toBe("");
126
234
  });
127
235
  });
128
236
 
@@ -200,6 +308,34 @@ describe("RuntimeManager", () => {
200
308
 
201
309
  expect(result).toBe(false);
202
310
  });
311
+
312
+ it("should update config.url on redirect, stripping /health from pathname", async () => {
313
+ global.fetch = vi.fn().mockResolvedValue({
314
+ ok: true,
315
+ redirected: true,
316
+ url: "https://sandbox.example.com/health?some_value=abc123",
317
+ });
318
+
319
+ const runtime = new RuntimeManager(
320
+ {
321
+ ...mockConfig,
322
+ url: "https://backend.example.com/lazy?some_value=abc123",
323
+ },
324
+ true, // lazy — don't call init() in constructor
325
+ );
326
+ const result = await runtime.isHealthy();
327
+
328
+ expect(result).toBe(true);
329
+ // Should strip /health from pathname but preserve query params
330
+ const wsUrl = runtime.getWsURL("s_test" as SessionId);
331
+ expect(wsUrl.pathname).toBe("/ws");
332
+ expect(wsUrl.hostname).toBe("sandbox.example.com");
333
+ expect(wsUrl.searchParams.get("some_value")).toBe("abc123");
334
+
335
+ // Clean up side effects
336
+ document.querySelectorAll("base").forEach((el) => el.remove());
337
+ global.fetch = vi.fn().mockResolvedValue({ ok: false });
338
+ });
203
339
  });
204
340
 
205
341
  describe("waitForHealthy", () => {
@@ -88,6 +88,15 @@ export class RuntimeManager {
88
88
  searchParams,
89
89
  /* restrictToKnownQueryParams =*/ false,
90
90
  );
91
+
92
+ // For cross-origin runtimes, pass the auth token as a query parameter.
93
+ // WebSocket connections cannot send custom headers (no Authorization
94
+ // header), and cross-origin cookies are blocked by browsers, so the
95
+ // access_token query param is the only way to authenticate.
96
+ if (!this.isSameOrigin && this.config.authToken) {
97
+ url.searchParams.set(KnownQueryParams.accessToken, this.config.authToken);
98
+ }
99
+
91
100
  return asWsUrl(url.toString());
92
101
  }
93
102
 
@@ -143,9 +152,15 @@ export class RuntimeManager {
143
152
  */
144
153
  getLSPURL(lsp: "pylsp" | "basedpyright" | "copilot" | "ty" | "pyrefly"): URL {
145
154
  if (lsp === "copilot") {
146
- // For copilot, don't include any query parameters
155
+ // For copilot, strip all query parameters except the auth token.
156
+ // Copilot doesn't understand arbitrary query params, but we still
157
+ // need access_token for cross-origin authentication.
147
158
  const url = this.formatWsURL(`/lsp/${lsp}`);
159
+ const accessToken = url.searchParams.get(KnownQueryParams.accessToken);
148
160
  url.search = "";
161
+ if (accessToken) {
162
+ url.searchParams.set(KnownQueryParams.accessToken, accessToken);
163
+ }
149
164
  return url;
150
165
  }
151
166
  return this.formatWsURL(`/lsp/${lsp}`);
@@ -173,9 +188,10 @@ export class RuntimeManager {
173
188
  // If there is a redirect, update the URL in the config
174
189
  if (response.redirected) {
175
190
  Logger.debug(`Runtime redirected to ${response.url}`);
176
- // strip /health from the URL
177
- const baseUrl = response.url.replace(/\/health$/, "");
178
- this.config.url = baseUrl;
191
+ // strip /health from the URL, using URL parsing to handle query params
192
+ const redirected = new URL(response.url);
193
+ redirected.pathname = redirected.pathname.replace(/\/health$/, "");
194
+ this.config.url = redirected.toString();
179
195
  }
180
196
 
181
197
  const success = response.ok;
@@ -183,7 +199,11 @@ export class RuntimeManager {
183
199
  this.setDOMBaseUri(this.config.url);
184
200
  }
185
201
  return success;
186
- } catch {
202
+ } catch (error) {
203
+ Logger.error(
204
+ `Failed to check health: ${error instanceof Error ? error.message : "Unknown error"}`,
205
+ { cause: error },
206
+ );
187
207
  return false;
188
208
  }
189
209
  }
@@ -16,6 +16,22 @@ export const filenameAtom = atom<string | null>(getFilenameFromDOM());
16
16
  */
17
17
  export const cwdAtom = atom<string | null>(null);
18
18
 
19
+ /**
20
+ * LSP workspace information from the backend.
21
+ * Contains the project root and the document's file URI.
22
+ */
23
+ export interface LspWorkspace {
24
+ rootUri: string;
25
+ documentUri: string;
26
+ }
27
+
28
+ /**
29
+ * Atom for storing the LSP workspace information.
30
+ * This is populated during active notebook sessions
31
+ * and null for other pages.
32
+ */
33
+ export const lspWorkspaceAtom = atom<LspWorkspace | null>(null);
34
+
19
35
  /**
20
36
  * Set for static notebooks.
21
37
  */
@@ -341,7 +341,7 @@ export function useAsyncData<T>(
341
341
  };
342
342
  setResult((prevResult) => {
343
343
  // If we have previous data, show reloading state
344
- if (prevResult.status === "success") {
344
+ if (prevResult.status === "success" || prevResult.status === "loading") {
345
345
  return Result.loading(prevResult.data);
346
346
  }
347
347
  // Otherwise, show initial loading state
package/src/mount.tsx CHANGED
@@ -36,7 +36,12 @@ import {
36
36
  DEFAULT_RUNTIME_CONFIG,
37
37
  runtimeConfigAtom,
38
38
  } from "./core/runtime/config";
39
- import { codeAtom, cwdAtom, filenameAtom } from "./core/saving/file-state";
39
+ import {
40
+ codeAtom,
41
+ cwdAtom,
42
+ filenameAtom,
43
+ lspWorkspaceAtom,
44
+ } from "./core/saving/file-state";
40
45
  import { store } from "./core/state/jotai";
41
46
  import { patchFetch, patchVegaLoader } from "./core/static/files";
42
47
  import {
@@ -150,6 +155,16 @@ const mountOptionsSchema = z.object({
150
155
  * absolute working directory of the notebook
151
156
  */
152
157
  cwd: z.string().nullish().default(null),
158
+ /**
159
+ * LSP workspace information
160
+ */
161
+ lspWorkspace: z
162
+ .object({
163
+ rootUri: z.string(),
164
+ documentUri: z.string(),
165
+ })
166
+ .nullish()
167
+ .default(null),
153
168
  /**
154
169
  * notebook code
155
170
  */
@@ -287,6 +302,7 @@ function initStore(options: unknown) {
287
302
  // Files
288
303
  store.set(filenameAtom, parsedOptions.data.filename);
289
304
  store.set(cwdAtom, parsedOptions.data.cwd ?? null);
305
+ store.set(lspWorkspaceAtom, parsedOptions.data.lspWorkspace);
290
306
  store.set(codeAtom, parsedOptions.data.code);
291
307
  store.set(initialModeAtom, mode);
292
308
 
@@ -704,7 +704,7 @@ export const LoadingDataTableComponent = memo(
704
704
  <LoadingTable
705
705
  pageSize={
706
706
  props.totalRows !== TOO_MANY_ROWS && props.totalRows > 0
707
- ? props.totalRows
707
+ ? Math.min(props.totalRows, props.pageSize)
708
708
  : props.pageSize
709
709
  }
710
710
  />
@@ -117,6 +117,14 @@ describe("shouldHandleClickSelection", () => {
117
117
  expect(shouldHandleClickSelection([linePoint])).toBe(true);
118
118
  });
119
119
 
120
+ it("accepts waterfall clicks", () => {
121
+ const waterfallPoint = createPlotDatum({
122
+ data: { type: "waterfall" },
123
+ });
124
+
125
+ expect(shouldHandleClickSelection([waterfallPoint])).toBe(true);
126
+ });
127
+
120
128
  it("rejects non-line scatter marker clicks", () => {
121
129
  const markerPoint = createPlotDatum({
122
130
  data: { type: "scatter", mode: "markers" },
@@ -196,4 +204,18 @@ describe("extractPoints", () => {
196
204
 
197
205
  expect(extractPoints([point])).toEqual([{ x: 1, y: 2, z: 3 }]);
198
206
  });
207
+
208
+ it("returns x/y/pointIndex for waterfall clicks", () => {
209
+ const point = createPlotDatum({
210
+ x: "Revenue",
211
+ y: 400,
212
+ pointIndex: 1,
213
+ curveNumber: 0,
214
+ data: { type: "waterfall" },
215
+ });
216
+
217
+ expect(extractPoints([point])).toEqual([
218
+ { x: "Revenue", y: 400, pointIndex: 1, curveNumber: 0 },
219
+ ]);
220
+ });
199
221
  });
@@ -227,6 +227,7 @@ export function shouldHandleClickSelection(
227
227
  type === "bar" ||
228
228
  type === "heatmap" ||
229
229
  type === "histogram" ||
230
+ type === "waterfall" ||
230
231
  isLinePoint(point)
231
232
  );
232
233
  });