diff --git a/src/extensions/notebook/notebook-block-code.tsx b/src/extensions/notebook/notebook-block-code.tsx index 5b97dcca..e9eaeb8f 100644 --- a/src/extensions/notebook/notebook-block-code.tsx +++ b/src/extensions/notebook/notebook-block-code.tsx @@ -3,12 +3,21 @@ import { NotebookEditorBlockValue } from "./notebook-editor"; import { NotebookVM } from "./notebook-vm"; import JavascriptEditor from "@/components/editor/javascript-editor"; import { Button } from "@/components/ui/button"; -import { LucideShieldAlert, PlayIcon, Terminal } from "lucide-react"; +import { + LucideLoader, + LucideShieldAlert, + LucideTerminal, + PlayIcon, + Terminal, +} from "lucide-react"; import { produce } from "immer"; import { cn } from "@/lib/utils"; -interface OutputFormat { - type: "log"; +export interface NotebookOutputFormat { + id?: string; + type: "log" | "error" | "query"; + sql?: string; + queryStatus?: "running" | "success" | "error"; args: unknown[]; } @@ -42,25 +51,53 @@ function OutputArgItem({ value }: { value: unknown }) { return {content}; } -function OutputItem({ value }: { value: OutputFormat }) { - const color = value.type === "log" ? "" : "text-red-400 dark:text-red-300"; +function OutputItem({ value }: { value: NotebookOutputFormat }) { + if (value.type === "query") { + let icon = ; + let color = ""; - return ( -
- {value.type === "log" ? ( -
- ) : ( + if (value.queryStatus === "success") { + icon = ; + color = "text-green-600 dark:text-green-400"; + } else if (value.queryStatus === "error") { + icon = ; + color = "text-red-400 dark:text-red-300"; + } + + return ( +
+
{icon}
+
+          
+          {value.sql}
+        
+
+ ); + } else if (value.type === "error") { + return ( +
- )} -
-        {value.args.map((argValue, argIndex) => (
-          
-        ))}
-      
-
- ); +
+          {value.args.map((argValue, argIndex) => (
+            
+          ))}
+        
+
+ ); + } else { + return ( +
+
+
+          {value.args.map((argValue, argIndex) => (
+            
+          ))}
+        
+
+ ); + } } export default function NotebookBlockCode({ @@ -72,7 +109,7 @@ export default function NotebookBlockCode({ value: NotebookEditorBlockValue; onChange: (value: NotebookEditorBlockValue) => void; }) { - const [output, setOutput] = useState([]); + const [output, setOutput] = useState([]); const onRunClick = () => { setOutput([]); @@ -80,11 +117,12 @@ export default function NotebookBlockCode({ complete: () => { console.log("Complete"); }, - stdOut: (data: any) => { - setOutput((prev) => [...prev, data]); - }, - stdErr: () => { - console.log("Error"); + stdOut: (data) => { + if (data.id) { + setOutput((prev) => [...prev.filter((p) => p.id !== data.id), data]); + } else { + setOutput((prev) => [...prev, data]); + } }, }); }; diff --git a/src/extensions/notebook/notebook-editor.tsx b/src/extensions/notebook/notebook-editor.tsx index 3b824bd1..2d8f98f6 100644 --- a/src/extensions/notebook/notebook-editor.tsx +++ b/src/extensions/notebook/notebook-editor.tsx @@ -47,7 +47,7 @@ export default function NotebookEditor() { value: `for(let i = 0; i < 5; i++) { await sleep(1000); const age = Math.floor(Math.random() * 100)); - const name = "name \${i}"; + const name = \`name \${i}\`; await query(\`INSERT INTO testing(name, age) VALUES ('\${name}', \${age})\`); console.log("Inserting", name, age); }`, diff --git a/src/extensions/notebook/notebook-vm.tsx b/src/extensions/notebook/notebook-vm.tsx index 33f90485..448d5ee7 100644 --- a/src/extensions/notebook/notebook-vm.tsx +++ b/src/extensions/notebook/notebook-vm.tsx @@ -1,5 +1,6 @@ import { BaseDriver } from "@/drivers/base-driver"; import { useEffect, useMemo } from "react"; +import { NotebookOutputFormat } from "./notebook-block-code"; const workerCode = ` let scope = {}; @@ -52,16 +53,14 @@ const workerCode = ` interface RunOpions { complete?: () => void; - stdOut?: (data: T) => void; - stdErr?: () => void; + stdOut?: (data: NotebookOutputFormat) => void; } export class NotebookVM { protected vm: Worker; protected driver: BaseDriver; protected onComplete?: () => void; - protected onStdOut?: (data: T) => void; - protected onStdErr?: () => void; + protected onStdOut?: (data: NotebookOutputFormat) => void; constructor(vm: Worker, driver: BaseDriver) { this.vm = vm; @@ -71,21 +70,25 @@ export class NotebookVM { const { type } = e.data; if (type === "log" || type === "error") { - if (this.onStdOut) { - this.onStdOut(e.data); - } + if (this.onStdOut) this.onStdOut(e.data); } else if (type === "query") { + if (this.onStdOut) this.onStdOut({ ...e.data, queryStatus: "running" }); + this.driver .query(e.data.sql) .then((result) => { - console.log("Got it result", result); this.vm.postMessage({ type: "query_result", id: e.data.id, result: result, }); + if (this.onStdOut) + this.onStdOut({ ...e.data, queryStatus: "success" }); }) .catch((error) => { + if (this.onStdOut) + this.onStdOut({ ...e.data, queryStatus: "error" }); + if (error instanceof Error) { this.vm.postMessage({ type: "query_result", @@ -111,7 +114,6 @@ export class NotebookVM { run(code: string, options: RunOpions): void { this.onComplete = options.complete; this.onStdOut = options.stdOut; - this.onStdErr = options.stdErr; this.vm.postMessage({ type: "eval",