@marimo-team/frontend 0.14.18-dev37 → 0.14.18-dev39
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/assets/{ConnectedDataExplorerComponent-C3k5hPLu.js → ConnectedDataExplorerComponent-Dluf8clT.js} +1 -1
- package/dist/assets/{ImageComparisonComponent-BjOFN8jM.js → ImageComparisonComponent-CK_fmBK6.js} +1 -1
- package/dist/assets/{VegaLite-DgJ7jnLw.js → VegaLite-GAUrkYuV.js} +1 -1
- package/dist/assets/{_baseEach-pzHGHEY4.js → _baseEach-C0Sqwj1Y.js} +1 -1
- package/dist/assets/_baseMap-wbAXOiz5.js +1 -0
- package/dist/assets/{_baseUniq-CQItUkLS.js → _baseUniq-C6CtZ9jJ.js} +1 -1
- package/dist/assets/{_createAggregator-D-uitHtz.js → _createAggregator-DCg3aG5g.js} +1 -1
- package/dist/assets/{any-language-editor-Cmq3ciWC.js → any-language-editor-C1hAvQU_.js} +1 -1
- package/dist/assets/{architectureDiagram-SUXI7LT5-BO-3YmEX.js → architectureDiagram-SUXI7LT5-CY6ZXfK5.js} +1 -1
- package/dist/assets/{blockDiagram-6J76NXCF-Dt5N8bX3.js → blockDiagram-6J76NXCF-BfT_qzzN.js} +1 -1
- package/dist/assets/{c4Diagram-6F6E4RAY-zW8gkeE8.js → c4Diagram-6F6E4RAY-BNmm8mbN.js} +1 -1
- package/dist/assets/channel-p2n1Ehs7.js +1 -0
- package/dist/assets/{chunk-353BL4L5-DTHrwX0H.js → chunk-353BL4L5-BD1eYYEv.js} +1 -1
- package/dist/assets/{chunk-67H74DCK-BLaovY1-.js → chunk-67H74DCK-D32ZcVIe.js} +1 -1
- package/dist/assets/{chunk-AACKK3MU-DJFY0X5n.js → chunk-AACKK3MU-VRjqE2eS.js} +1 -1
- package/dist/assets/{chunk-BFAMUDN2-LzixKanE.js → chunk-BFAMUDN2-C-cJmQLf.js} +1 -1
- package/dist/assets/{chunk-E2GYISFI-B-672zyq.js → chunk-E2GYISFI-BVyg2Fo6.js} +1 -1
- package/dist/assets/{chunk-OW32GOEJ-CJecFYpV.js → chunk-OW32GOEJ-CJAy1Ibj.js} +1 -1
- package/dist/assets/{chunk-SKB7J2MH-CD0WbCzI.js → chunk-SKB7J2MH-CNnoGuDT.js} +1 -1
- package/dist/assets/{chunk-SZ463SBG-pTDg_1jk.js → chunk-SZ463SBG-B-DyRJ-t.js} +1 -1
- package/dist/assets/{circle-play-D6EUBkp5.js → circle-play-DlcQmjy-.js} +1 -1
- package/dist/assets/classDiagram-M3E45YP4-CvCuraNp.js +1 -0
- package/dist/assets/classDiagram-v2-YAWTLIQI-CvCuraNp.js +1 -0
- package/dist/assets/clone-CglRxjPg.js +1 -0
- package/dist/assets/{compile-naE2cSaS.js → compile-Da_Fjkgs.js} +1 -1
- package/dist/assets/{dagre-JOIXM2OF-BGYi4rRz.js → dagre-JOIXM2OF-B6XR4pJX.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-C03UhjBo.js → data-grid-overlay-editor-v4eNCtyj.js} +1 -1
- package/dist/assets/{diagram-5UYTHUR4-DfPUdpUn.js → diagram-5UYTHUR4-fJ5HfR4m.js} +1 -1
- package/dist/assets/{diagram-VMROVX33-DIE6r0im.js → diagram-VMROVX33-j3xejCo0.js} +1 -1
- package/dist/assets/{diagram-ZTM2IBQH-CEBREHFr.js → diagram-ZTM2IBQH-dkgnTPsZ.js} +1 -1
- package/dist/assets/{edit-page-DJJejvk6.js → edit-page-CmCSSEmo.js} +38 -38
- package/dist/assets/{erDiagram-3M52JZNH-B4NhsuE8.js → erDiagram-3M52JZNH-pjMXU-CR.js} +1 -1
- package/dist/assets/{flowDiagram-KYDEHFYC-jZGD-hHQ.js → flowDiagram-KYDEHFYC-RFXKcK0k.js} +1 -1
- package/dist/assets/{ganttDiagram-EK5VF46D-ByS2LJXk.js → ganttDiagram-EK5VF46D-BgmOCQC2.js} +1 -1
- package/dist/assets/{gitGraphDiagram-GW3U2K7C-DPpl9bW7.js → gitGraphDiagram-GW3U2K7C-DQPA3IzE.js} +1 -1
- package/dist/assets/{glide-data-editor-Ctp5cb01.js → glide-data-editor-DWBodoS3.js} +4 -4
- package/dist/assets/{graph-D8hCRiO-.js → graph-DacIO-UV.js} +1 -1
- package/dist/assets/{home-page-BOha11wZ.js → home-page-CRXrPrxk.js} +1 -1
- package/dist/assets/{index-DkT396dR.js → index-8RrfVV3p.js} +1 -1
- package/dist/assets/{index-DvLglJGf.js → index-BC3mHcN4.js} +1 -1
- package/dist/assets/{index-B-V9jaSp.js → index-BDUp_sLz.js} +1 -1
- package/dist/assets/{index-CC2E3f4Q.js → index-BHV0wUT7.js} +181 -180
- package/dist/assets/{index-BoHmD2lN.js → index-BQF1L3gh.js} +1 -1
- package/dist/assets/{index-hx9zD-F8.js → index-BRCKCYPN.js} +1 -1
- package/dist/assets/{index-P2Xevp4g.js → index-BXCylVut.js} +1 -1
- package/dist/assets/{index-F8A7jFRS.js → index-Bg24ojRl.js} +1 -1
- package/dist/assets/{index-B0m8evbg.js → index-BoaOUG3q.js} +1 -1
- package/dist/assets/{index-LNINpf1O.js → index-BxSZURSP.js} +1 -1
- package/dist/assets/{index-CXYh_vqL.js → index-BxjU6sz1.js} +1 -1
- package/dist/assets/{index-CAHCwUFF.js → index-C8_gM-Yh.js} +1 -1
- package/dist/assets/{index-B0uP21nC.js → index-CRoIS0e_.js} +1 -1
- package/dist/assets/index-CrH6PPjG.css +1 -0
- package/dist/assets/{index-Cb7ino3i.js → index-D-j7DlKu.js} +1 -1
- package/dist/assets/{index-BeH3WPTC.js → index-D6Npa4_9.js} +1 -1
- package/dist/assets/{index-ChLKVpQ4.js → index-M577h3xO.js} +1 -1
- package/dist/assets/{index-Cw8iULrO.js → index-PXlQy2IY.js} +1 -1
- package/dist/assets/{index-CmCTzIMP.js → index-dlPsVpRk.js} +1 -1
- package/dist/assets/{index-BNAVkiFE.js → index-i68zQEWD.js} +1 -1
- package/dist/assets/{index-oUdxu43b.js → index-txOE5caF.js} +1 -1
- package/dist/assets/infoDiagram-LHK5PUON-BQo83J9q.js +2 -0
- package/dist/assets/{journeyDiagram-EWQZEKCU-CUqNznku.js → journeyDiagram-EWQZEKCU--vn5uP9G.js} +1 -1
- package/dist/assets/{kanban-definition-ZSS6B67P-wAX5kOcc.js → kanban-definition-ZSS6B67P-BsAtaVBp.js} +1 -1
- package/dist/assets/{layout-DHNLnBrk.js → layout-D89ZmFuH.js} +1 -1
- package/dist/assets/{linear-C4cm1cyD.js → linear--2JfAOS_.js} +1 -1
- package/dist/assets/links-DHuoq13s.js +17 -0
- package/dist/assets/{mermaid-Cyy1SuLp.js → mermaid-BbIb2iAQ.js} +4 -4
- package/dist/assets/{min-DEKMoQKx.js → min-B719_H4j.js} +1 -1
- package/dist/assets/{mindmap-definition-6CBA2TL7-BuKaCMZv.js → mindmap-definition-6CBA2TL7-DbrwDtvS.js} +1 -1
- package/dist/assets/{number-overlay-editor-D6ItVsoK.js → number-overlay-editor-VjmSOKWj.js} +1 -1
- package/dist/assets/{pieDiagram-NIOCPIFQ-CiiLyBIl.js → pieDiagram-NIOCPIFQ-DDr_8e6N.js} +1 -1
- package/dist/assets/{quadrantDiagram-2OG54O6I-C4fysEbE.js → quadrantDiagram-2OG54O6I-TFsW3qDt.js} +1 -1
- package/dist/assets/{react-plotly-xELLTGMb.js → react-plotly-BJBcptDR.js} +1 -1
- package/dist/assets/{requirementDiagram-QOLK2EJ7-BRxJBhke.js → requirementDiagram-QOLK2EJ7-D5BaSClp.js} +1 -1
- package/dist/assets/{run-page-BvmAfKi3.js → run-page-D1TeIIYq.js} +1 -1
- package/dist/assets/{sankeyDiagram-4UZDY2LN-7LEwluDj.js → sankeyDiagram-4UZDY2LN-B-zmPQdl.js} +1 -1
- package/dist/assets/{sequenceDiagram-SKLFT4DO-C0tnmVO0.js → sequenceDiagram-SKLFT4DO-Dw--eukV.js} +1 -1
- package/dist/assets/{slides-component-Bk9mtZB_.js → slides-component-CUV-ryNw.js} +1 -1
- package/dist/assets/{sortBy-Dfn-YbfY.js → sortBy-C9K5SL89.js} +1 -1
- package/dist/assets/{stateDiagram-MI5ZYTHO-CErzlFMf.js → stateDiagram-MI5ZYTHO-WTQoQzCe.js} +1 -1
- package/dist/assets/stateDiagram-v2-5AN5P6BG-CoRRGWzU.js +1 -0
- package/dist/assets/{storage-COfGEwjy.js → storage-BgxGjrlK.js} +3 -3
- package/dist/assets/{terminal-BBfg98Ck.js → terminal-BRsJ5bg0.js} +1 -1
- package/dist/assets/{time-mJaqTj1J.js → time-Wo8mRr4h.js} +1 -1
- package/dist/assets/{timeline-definition-MYPXXCX6-Adnqmrjd.js → timeline-definition-MYPXXCX6-DUiBvKXW.js} +1 -1
- package/dist/assets/{tracing-CRHBCgSH.js → tracing-DkTh5bjk.js} +2 -2
- package/dist/assets/{trash-Bzd1HHgn.js → trash-_cwoDPy1.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-CpWfdhdZ.js → treemap-75Q7IDZK-DndwJIAY.js} +1 -1
- package/dist/assets/{vega-component-D5DIeDhI.js → vega-component-BQrEMxr7.js} +1 -1
- package/dist/assets/{xychartDiagram-H2YORKM3-BOCS9pT9.js → xychartDiagram-H2YORKM3-Cn7nHPc6.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/components/ai/ai-model-dropdown.tsx +1 -1
- package/src/components/chat/chat-panel.tsx +8 -51
- package/src/components/editor/ai/add-cell-with-ai.tsx +114 -60
- package/src/components/editor/ai/ai-completion-editor.tsx +27 -15
- package/src/core/ai/config.ts +76 -0
- package/src/core/config/config-schema.ts +18 -12
- package/src/core/static/__tests__/files.test.ts +311 -0
- package/src/core/static/files.ts +35 -33
- package/src/plugins/impl/chat/chat-ui.tsx +0 -3
- package/dist/assets/_baseMap-D7704cQJ.js +0 -1
- package/dist/assets/channel-DIKq6rH6.js +0 -1
- package/dist/assets/classDiagram-M3E45YP4-ND3H63mC.js +0 -1
- package/dist/assets/classDiagram-v2-YAWTLIQI-ND3H63mC.js +0 -1
- package/dist/assets/clone-DTqdNqdv.js +0 -1
- package/dist/assets/index-BH8vrBOf.css +0 -1
- package/dist/assets/infoDiagram-LHK5PUON-BvsMfL6R.js +0 -2
- package/dist/assets/links-BqhBJqXV.js +0 -18
- package/dist/assets/stateDiagram-v2-5AN5P6BG-B5oy_bi9.js +0 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import http from "node:http";
|
|
5
5
|
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
|
6
6
|
import { createLoader } from "@/plugins/impl/vega/vega-loader";
|
|
7
|
+
import { Functions } from "@/utils/functions";
|
|
7
8
|
import type { DataURLString } from "@/utils/json/base64";
|
|
8
9
|
import { patchFetch, patchVegaLoader } from "../files";
|
|
9
10
|
|
|
@@ -83,6 +84,104 @@ describe("patchFetch", () => {
|
|
|
83
84
|
expect(text).toBe("hello,world\n");
|
|
84
85
|
}
|
|
85
86
|
});
|
|
87
|
+
|
|
88
|
+
it("should handle file:// URLs with @file/ paths", async () => {
|
|
89
|
+
const virtualFiles = {
|
|
90
|
+
"/@file/local-data.txt":
|
|
91
|
+
"data:text/plain;base64,TG9jYWwgZmlsZSBkYXRh" as DataURLString,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const unpatch = patchFetch(virtualFiles);
|
|
95
|
+
|
|
96
|
+
const response = await window.fetch(
|
|
97
|
+
"file:///Users/test/@file/local-data.txt",
|
|
98
|
+
);
|
|
99
|
+
const text = await response.text();
|
|
100
|
+
|
|
101
|
+
expect(text).toBe("Local file data");
|
|
102
|
+
expect(response.headers.get("Content-Type")).toBe("text/plain");
|
|
103
|
+
|
|
104
|
+
unpatch();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should handle blob: base URIs correctly", async () => {
|
|
108
|
+
// Mock document.baseURI to simulate blob: protocol
|
|
109
|
+
const originalBaseURI = document.baseURI;
|
|
110
|
+
Object.defineProperty(document, "baseURI", {
|
|
111
|
+
value: "blob:https://example.com/uuid",
|
|
112
|
+
configurable: true,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const virtualFiles = {
|
|
116
|
+
"/@file/blob-test.json":
|
|
117
|
+
"data:application/json;base64,eyJ0ZXN0IjogdHJ1ZX0=" as DataURLString,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
patchFetch(virtualFiles);
|
|
121
|
+
|
|
122
|
+
const response = await window.fetch("/@file/blob-test.json");
|
|
123
|
+
const text = await response.text();
|
|
124
|
+
|
|
125
|
+
expect(text).toBe('{"test": true}');
|
|
126
|
+
expect(response.headers.get("Content-Type")).toBe("application/json");
|
|
127
|
+
|
|
128
|
+
// Restore original baseURI
|
|
129
|
+
Object.defineProperty(document, "baseURI", {
|
|
130
|
+
value: originalBaseURI,
|
|
131
|
+
configurable: true,
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should handle various content types", async () => {
|
|
136
|
+
const virtualFiles = {
|
|
137
|
+
"/@file/test.csv": "data:text/csv;base64,YSxiLGMK" as DataURLString,
|
|
138
|
+
"/@file/test.json": "data:application/json;base64,e30K" as DataURLString,
|
|
139
|
+
"/@file/test.txt": "data:text/plain;base64,dGVzdA==" as DataURLString,
|
|
140
|
+
"/@file/test.bin":
|
|
141
|
+
"data:application/octet-stream;base64,AAECAwQ=" as DataURLString,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
patchFetch(virtualFiles);
|
|
145
|
+
|
|
146
|
+
const testCases = [
|
|
147
|
+
{ file: "/@file/test.csv", expectedType: "text/csv" },
|
|
148
|
+
{ file: "/@file/test.json", expectedType: "application/json" },
|
|
149
|
+
{ file: "/@file/test.txt", expectedType: "text/plain" },
|
|
150
|
+
{ file: "/@file/test.bin", expectedType: "application/octet-stream" },
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
for (const { file, expectedType } of testCases) {
|
|
154
|
+
const response = await window.fetch(file);
|
|
155
|
+
expect(response.headers.get("Content-Type")).toBe(expectedType);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should handle data: URLs directly without processing", async () => {
|
|
160
|
+
const virtualFiles = {};
|
|
161
|
+
patchFetch(virtualFiles);
|
|
162
|
+
|
|
163
|
+
const dataUrl = "data:text/plain;base64,SGVsbG8gV29ybGQ=";
|
|
164
|
+
const response = await window.fetch(dataUrl);
|
|
165
|
+
const text = await response.text();
|
|
166
|
+
|
|
167
|
+
expect(text).toBe("Hello World");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should handle error cases gracefully", async () => {
|
|
171
|
+
const virtualFiles = {};
|
|
172
|
+
const unpatch = patchFetch(virtualFiles);
|
|
173
|
+
|
|
174
|
+
// Mock Logger.error to avoid console output during tests
|
|
175
|
+
const loggerSpy = vi
|
|
176
|
+
.spyOn(console, "error")
|
|
177
|
+
.mockImplementation(Functions.NOOP);
|
|
178
|
+
|
|
179
|
+
// This should fallback to original fetch and potentially fail
|
|
180
|
+
await expect(window.fetch("invalid://url")).rejects.toThrow();
|
|
181
|
+
|
|
182
|
+
unpatch();
|
|
183
|
+
loggerSpy.mockRestore();
|
|
184
|
+
});
|
|
86
185
|
});
|
|
87
186
|
|
|
88
187
|
describe("patchVegaLoader - loader.http", () => {
|
|
@@ -180,4 +279,216 @@ describe("patchVegaLoader - loader.load", () => {
|
|
|
180
279
|
await expect(loader.load("/non-existent-file.json")).rejects.toThrow();
|
|
181
280
|
unpatch();
|
|
182
281
|
});
|
|
282
|
+
|
|
283
|
+
it("should handle file:// URLs with @file/ paths in loader.load", async () => {
|
|
284
|
+
const virtualFiles = {
|
|
285
|
+
"/@file/vega-data.json":
|
|
286
|
+
"data:application/json;base64,eyJ2YWx1ZXMiOiBbMSwgMiwgM119" as DataURLString,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const loader = createLoader();
|
|
290
|
+
const unpatch = patchVegaLoader(loader, virtualFiles);
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
const content = await loader.load("file:///path/to/@file/vega-data.json");
|
|
294
|
+
expect(content).toBe('{"values": [1, 2, 3]}');
|
|
295
|
+
} catch (error) {
|
|
296
|
+
// If it falls back to original loader and fails, that's expected for file:// URLs
|
|
297
|
+
// The important thing is that the virtual file lookup was attempted
|
|
298
|
+
expect(error).toBeDefined();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
unpatch();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should pass files parameter correctly to maybeGetVirtualFile in loader.load", async () => {
|
|
305
|
+
// This test ensures the bug fix where files parameter was missing
|
|
306
|
+
const virtualFiles = {
|
|
307
|
+
"/test-file.json":
|
|
308
|
+
"data:application/json;base64,eyJmaXhlZCI6IHRydWV9" as DataURLString,
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const loader = createLoader();
|
|
312
|
+
const unpatch = patchVegaLoader(loader, virtualFiles);
|
|
313
|
+
const content = await loader.load("/test-file.json");
|
|
314
|
+
unpatch();
|
|
315
|
+
|
|
316
|
+
expect(content).toBe('{"fixed": true}');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("should handle different URL patterns in loader.load", async () => {
|
|
320
|
+
const virtualFiles = {
|
|
321
|
+
"/@file/pattern-test.json":
|
|
322
|
+
"data:application/json;base64,eyJwYXR0ZXJuIjogInRlc3QifQ==" as DataURLString,
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
const loader = createLoader();
|
|
326
|
+
const unpatch = patchVegaLoader(loader, virtualFiles);
|
|
327
|
+
|
|
328
|
+
// Test URL patterns that should resolve to the same virtual file
|
|
329
|
+
const testUrls = [
|
|
330
|
+
"/@file/pattern-test.json",
|
|
331
|
+
"./@file/pattern-test.json",
|
|
332
|
+
"http://example.com/@file/pattern-test.json",
|
|
333
|
+
];
|
|
334
|
+
|
|
335
|
+
for (const url of testUrls) {
|
|
336
|
+
const content = await loader.load(url);
|
|
337
|
+
expect(content).toBe('{"pattern": "test"}');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Test file:// URL separately since it might fallback
|
|
341
|
+
try {
|
|
342
|
+
const content = await loader.load(
|
|
343
|
+
"file:///local/path/@file/pattern-test.json",
|
|
344
|
+
);
|
|
345
|
+
expect(content).toBe('{"pattern": "test"}');
|
|
346
|
+
} catch (error) {
|
|
347
|
+
// Expected if it falls back to original loader
|
|
348
|
+
expect(error).toBeDefined();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
unpatch();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
describe("maybeGetVirtualFile utility function", () => {
|
|
356
|
+
it("should handle URLs without leading dots correctly", async () => {
|
|
357
|
+
const virtualFiles = {
|
|
358
|
+
"/file.txt": "data:text/plain;base64,dGVzdA==" as DataURLString,
|
|
359
|
+
"file.txt": "data:text/plain;base64,dGVzdA==" as DataURLString,
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
patchFetch(virtualFiles);
|
|
363
|
+
|
|
364
|
+
// Both should work
|
|
365
|
+
const response1 = await window.fetch("./file.txt");
|
|
366
|
+
const response2 = await window.fetch("/file.txt");
|
|
367
|
+
|
|
368
|
+
const text1 = await response1.text();
|
|
369
|
+
const text2 = await response2.text();
|
|
370
|
+
|
|
371
|
+
expect(text1).toBe("test");
|
|
372
|
+
expect(text2).toBe("test");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("should handle complex file:// URLs with nested paths", async () => {
|
|
376
|
+
const virtualFiles = {
|
|
377
|
+
"/@file/nested/data.json":
|
|
378
|
+
"data:application/json;base64,eyJuZXN0ZWQiOiB0cnVlfQ==" as DataURLString,
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const unpatch = patchFetch(virtualFiles);
|
|
382
|
+
|
|
383
|
+
const response = await window.fetch(
|
|
384
|
+
"file:///Users/project/deep/path/@file/nested/data.json",
|
|
385
|
+
);
|
|
386
|
+
const text = await response.text();
|
|
387
|
+
|
|
388
|
+
expect(text).toBe('{"nested": true}');
|
|
389
|
+
|
|
390
|
+
unpatch();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("should handle URLs when @file/ is not found in file:// URLs", async () => {
|
|
394
|
+
const virtualFiles = {
|
|
395
|
+
"/@file/test.txt": "data:text/plain;base64,dGVzdA==" as DataURLString,
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const unpatch = patchFetch(virtualFiles);
|
|
399
|
+
|
|
400
|
+
// This file:// URL doesn't contain @file/, so it should fallback to original fetch
|
|
401
|
+
await expect(
|
|
402
|
+
window.fetch("file:///simple/path/test.txt"),
|
|
403
|
+
).rejects.toThrow();
|
|
404
|
+
|
|
405
|
+
unpatch();
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
describe("error handling and edge cases", () => {
|
|
410
|
+
it("should restore original functions after unpatch", async () => {
|
|
411
|
+
const originalFetch = window.fetch;
|
|
412
|
+
const loader = createLoader();
|
|
413
|
+
|
|
414
|
+
const unpatchFetch = patchFetch({});
|
|
415
|
+
const unpatchLoader = patchVegaLoader(loader, {});
|
|
416
|
+
|
|
417
|
+
// Functions should be patched
|
|
418
|
+
expect(window.fetch).not.toBe(originalFetch);
|
|
419
|
+
|
|
420
|
+
// Test that the patched functions work
|
|
421
|
+
const virtualFiles = {
|
|
422
|
+
"/@file/test.txt": "data:text/plain;base64,dGVzdA==" as DataURLString,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// Re-patch with test data
|
|
426
|
+
unpatchFetch();
|
|
427
|
+
unpatchLoader();
|
|
428
|
+
|
|
429
|
+
const unpatchFetch2 = patchFetch(virtualFiles);
|
|
430
|
+
const unpatchLoader2 = patchVegaLoader(loader, virtualFiles);
|
|
431
|
+
|
|
432
|
+
// Test functionality works
|
|
433
|
+
const response = await window.fetch("/@file/test.txt");
|
|
434
|
+
const text = await response.text();
|
|
435
|
+
expect(text).toBe("test");
|
|
436
|
+
|
|
437
|
+
const content = await loader.load("/@file/test.txt");
|
|
438
|
+
expect(content).toBe("test");
|
|
439
|
+
|
|
440
|
+
unpatchFetch2();
|
|
441
|
+
unpatchLoader2();
|
|
442
|
+
|
|
443
|
+
// Functions should be restored
|
|
444
|
+
expect(window.fetch).toBe(originalFetch);
|
|
445
|
+
|
|
446
|
+
// Test that the loader functions are functional (they should work normally)
|
|
447
|
+
try {
|
|
448
|
+
await loader.load("http://example.com/test.json");
|
|
449
|
+
} catch (error) {
|
|
450
|
+
// Expected to fail for non-existent URLs, but the function should be callable
|
|
451
|
+
expect(error).toBeDefined();
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it("should handle Request objects in patchFetch", async () => {
|
|
456
|
+
const virtualFiles = {
|
|
457
|
+
"/@file/request-test.txt":
|
|
458
|
+
"data:text/plain;base64,UmVxdWVzdCB0ZXN0" as DataURLString,
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const unpatch = patchFetch(virtualFiles);
|
|
462
|
+
|
|
463
|
+
// Use a full URL for the Request constructor
|
|
464
|
+
const request = new Request("http://example.com/@file/request-test.txt");
|
|
465
|
+
const response = await window.fetch(request);
|
|
466
|
+
const text = await response.text();
|
|
467
|
+
|
|
468
|
+
expect(text).toBe("Request test");
|
|
469
|
+
|
|
470
|
+
unpatch();
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it("should handle malformed URLs gracefully", async () => {
|
|
474
|
+
const virtualFiles = {};
|
|
475
|
+
const unpatch = patchFetch(virtualFiles);
|
|
476
|
+
|
|
477
|
+
// Mock Logger.error to avoid test output
|
|
478
|
+
const loggerSpy = vi
|
|
479
|
+
.spyOn(console, "error")
|
|
480
|
+
.mockImplementation(Functions.NOOP);
|
|
481
|
+
|
|
482
|
+
// This should catch the error and fallback to original fetch
|
|
483
|
+
try {
|
|
484
|
+
await window.fetch("not-a-valid-url");
|
|
485
|
+
// If it doesn't throw, that's also fine (fallback behavior)
|
|
486
|
+
} catch (error) {
|
|
487
|
+
// Expected behavior - invalid URLs should be handled gracefully
|
|
488
|
+
expect(error).toBeDefined();
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
unpatch();
|
|
492
|
+
loggerSpy.mockRestore();
|
|
493
|
+
});
|
|
183
494
|
});
|
package/src/core/static/files.ts
CHANGED
|
@@ -24,20 +24,15 @@ export function patchFetch(
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
: new URL(urlString);
|
|
31
|
-
|
|
32
|
-
const filePath = url.pathname;
|
|
33
|
-
if (files[filePath]) {
|
|
34
|
-
const base64 = files[filePath];
|
|
27
|
+
const vfile = maybeGetVirtualFile(urlString, files);
|
|
28
|
+
if (vfile) {
|
|
29
|
+
const base64 = vfile;
|
|
35
30
|
// Convert data URL to blob
|
|
36
31
|
const response = await originalFetch(base64);
|
|
37
32
|
const blob = await response.blob();
|
|
38
33
|
return new Response(blob, {
|
|
39
34
|
headers: {
|
|
40
|
-
"Content-Type": getContentType(
|
|
35
|
+
"Content-Type": getContentType(urlString),
|
|
41
36
|
},
|
|
42
37
|
});
|
|
43
38
|
}
|
|
@@ -77,30 +72,8 @@ export function patchVegaLoader(
|
|
|
77
72
|
const originalHttp = loader.http.bind(loader);
|
|
78
73
|
const originalLoad = loader.load.bind(loader);
|
|
79
74
|
|
|
80
|
-
function maybeGetVirtualFile(url: string): string | undefined {
|
|
81
|
-
const pathname = new URL(url, document.baseURI).pathname;
|
|
82
|
-
|
|
83
|
-
// If if the URL starts with file://, then using the document.baseURI
|
|
84
|
-
// will not work. In this case, should just chop off from /@file/...
|
|
85
|
-
if (url.startsWith("file://")) {
|
|
86
|
-
const indexOfFile = url.indexOf("/@file/");
|
|
87
|
-
if (indexOfFile !== -1) {
|
|
88
|
-
url = files[url.slice(indexOfFile)];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Few variations to grab the URL.
|
|
93
|
-
// This can happen if a static file was open at file:// or https://
|
|
94
|
-
return (
|
|
95
|
-
files[url] ||
|
|
96
|
-
files[withoutLeadingDot(url)] ||
|
|
97
|
-
files[pathname] ||
|
|
98
|
-
files[withoutLeadingDot(pathname)]
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
75
|
loader.http = async (url: string) => {
|
|
103
|
-
const vfile = maybeGetVirtualFile(url);
|
|
76
|
+
const vfile = maybeGetVirtualFile(url, files);
|
|
104
77
|
if (vfile) {
|
|
105
78
|
// If the file is a virtual file, fetch it
|
|
106
79
|
return await window.fetch(vfile).then((r) => r.text());
|
|
@@ -119,7 +92,7 @@ export function patchVegaLoader(
|
|
|
119
92
|
};
|
|
120
93
|
|
|
121
94
|
loader.load = async (url: string) => {
|
|
122
|
-
const vfile = maybeGetVirtualFile(url);
|
|
95
|
+
const vfile = maybeGetVirtualFile(url, files);
|
|
123
96
|
if (vfile) {
|
|
124
97
|
// If the file is a virtual file, fetch it
|
|
125
98
|
return await window.fetch(vfile).then((r) => r.text());
|
|
@@ -146,3 +119,32 @@ export function patchVegaLoader(
|
|
|
146
119
|
function withoutLeadingDot(path: string): string {
|
|
147
120
|
return path.startsWith(".") ? path.slice(1) : path;
|
|
148
121
|
}
|
|
122
|
+
|
|
123
|
+
function maybeGetVirtualFile(
|
|
124
|
+
url: string,
|
|
125
|
+
files: StaticVirtualFiles,
|
|
126
|
+
): string | undefined {
|
|
127
|
+
let base = document.baseURI;
|
|
128
|
+
if (base.startsWith("blob:")) {
|
|
129
|
+
base = base.replace("blob:", "");
|
|
130
|
+
}
|
|
131
|
+
const pathname = new URL(url, base).pathname;
|
|
132
|
+
|
|
133
|
+
// If if the URL starts with file://, then using the document.baseURI
|
|
134
|
+
// will not work. In this case, should just chop off from /@file/...
|
|
135
|
+
if (url.startsWith("file://")) {
|
|
136
|
+
const indexOfFile = url.indexOf("/@file/");
|
|
137
|
+
if (indexOfFile !== -1) {
|
|
138
|
+
url = url.slice(indexOfFile);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Few variations to grab the URL.
|
|
143
|
+
// This can happen if a static file was open at file:// or https://
|
|
144
|
+
return (
|
|
145
|
+
files[url] ||
|
|
146
|
+
files[withoutLeadingDot(url)] ||
|
|
147
|
+
files[pathname] ||
|
|
148
|
+
files[withoutLeadingDot(pathname)]
|
|
149
|
+
);
|
|
150
|
+
}
|
|
@@ -43,7 +43,6 @@ import { toast } from "@/components/ui/use-toast";
|
|
|
43
43
|
import { moveToEndOfEditor } from "@/core/codemirror/utils";
|
|
44
44
|
import { useAsyncData } from "@/hooks/useAsyncData";
|
|
45
45
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
46
|
-
import { useTheme } from "@/theme/useTheme";
|
|
47
46
|
import { cn } from "@/utils/cn";
|
|
48
47
|
import { copyToClipboard } from "@/utils/copy";
|
|
49
48
|
import { Logger } from "@/utils/Logger";
|
|
@@ -74,7 +73,6 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
74
73
|
const formRef = useRef<HTMLFormElement>(null);
|
|
75
74
|
const codeMirrorInputRef = useRef<ReactCodeMirrorRef>(null);
|
|
76
75
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
77
|
-
const { theme } = useTheme();
|
|
78
76
|
|
|
79
77
|
const { data: initialMessages } = useAsyncData(async () => {
|
|
80
78
|
const chatMessages = await props.get_chat_history({});
|
|
@@ -374,7 +372,6 @@ export const Chatbot: React.FC<Props> = (props) => {
|
|
|
374
372
|
placeholder={promptInputPlaceholder}
|
|
375
373
|
value={input}
|
|
376
374
|
inputRef={codeMirrorInputRef}
|
|
377
|
-
theme={theme}
|
|
378
375
|
maxHeight={props.maxHeight ? `${props.maxHeight / 2}px` : undefined}
|
|
379
376
|
onChange={setInput}
|
|
380
377
|
onSubmit={(_evt, newValue) => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as m}from"./_baseEach-pzHGHEY4.js";import{x as s}from"./index-CC2E3f4Q.js";function e(r,o){var a=-1,t=s(r)?Array(r.length):[];return m(r,function(n,f,i){t[++a]=o(n,f,i)}),t}export{e as b};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as s,C as o}from"./mermaid-Cyy1SuLp.js";const n=(a,r)=>s.lang.round(o.parse(a)[r]);export{n as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as t,C as o}from"./chunk-SZ463SBG-pTDg_1jk.js";import{_ as e}from"./mermaid-Cyy1SuLp.js";import"./transform-B8bpuzxV.js";import"./chunk-E2GYISFI-B-672zyq.js";import"./chunk-BFAMUDN2-LzixKanE.js";import"./chunk-SKB7J2MH-CD0WbCzI.js";import"./index-CC2E3f4Q.js";import"./step-BwsUM5iJ.js";import"./timer-BwIYMJWC.js";var i={parser:t,get db(){return new o},renderer:s,styles:a,init:e(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{i as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as t,C as o}from"./chunk-SZ463SBG-pTDg_1jk.js";import{_ as e}from"./mermaid-Cyy1SuLp.js";import"./transform-B8bpuzxV.js";import"./chunk-E2GYISFI-B-672zyq.js";import"./chunk-BFAMUDN2-LzixKanE.js";import"./chunk-SKB7J2MH-CD0WbCzI.js";import"./index-CC2E3f4Q.js";import"./step-BwsUM5iJ.js";import"./timer-BwIYMJWC.js";var i={parser:t,get db(){return new o},renderer:s,styles:a,init:e(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{i as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as n}from"./_baseUniq-CQItUkLS.js";function o(r){return n(r,4)}export{o as c};
|