import { cn, generateUUID } from '@/lib/utils'; import { ClockRewind, CopyIcon, PlayIcon, RedoIcon, UndoIcon } from './icons'; import { Button } from './ui/button'; import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'; import { useCopyToClipboard } from 'usehooks-ts'; import { toast } from 'sonner'; import { ConsoleOutput, UIBlock } from './block'; import { Dispatch, memo, SetStateAction, startTransition, useCallback, useState, } from 'react'; interface BlockActionsProps { block: UIBlock; handleVersionChange: (type: 'next' | 'prev' | 'toggle' | 'latest') => void; currentVersionIndex: number; isCurrentVersion: boolean; mode: 'read-only' | 'edit' | 'diff'; setConsoleOutputs: Dispatch>>; } export function RunCodeButton({ block, setConsoleOutputs, }: { block: UIBlock; setConsoleOutputs: Dispatch>>; }) { const [pyodide, setPyodide] = useState(null); const isPython = true; const codeContent = block.content; const updateConsoleOutput = useCallback( (runId: string, content: string | null, status: 'completed' | 'failed') => { setConsoleOutputs((consoleOutputs) => { const index = consoleOutputs.findIndex((output) => output.id === runId); if (index === -1) return consoleOutputs; const updatedOutputs = [...consoleOutputs]; updatedOutputs[index] = { id: runId, content, status, }; return updatedOutputs; }); }, [setConsoleOutputs], ); const loadAndRunPython = useCallback(async () => { const runId = generateUUID(); setConsoleOutputs((consoleOutputs) => [ ...consoleOutputs, { id: runId, content: null, status: 'in_progress', }, ]); let currentPyodideInstance = pyodide; if (isPython) { if (!currentPyodideInstance) { // @ts-expect-error - pyodide is not defined const newPyodideInstance = await loadPyodide({ indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.23.4/full/', }); setPyodide(newPyodideInstance); currentPyodideInstance = newPyodideInstance; } try { await currentPyodideInstance.runPythonAsync(` import sys import io sys.stdout = io.StringIO() `); await currentPyodideInstance.runPythonAsync(codeContent); const output: string = await currentPyodideInstance.runPythonAsync( `sys.stdout.getvalue()`, ); updateConsoleOutput(runId, output, 'completed'); } catch (error: any) { updateConsoleOutput(runId, error.message, 'failed'); } } }, [pyodide, codeContent, isPython, setConsoleOutputs, updateConsoleOutput]); return ( ); } function PureBlockActions({ block, handleVersionChange, currentVersionIndex, isCurrentVersion, mode, setConsoleOutputs, }: BlockActionsProps) { const [_, copyToClipboard] = useCopyToClipboard(); return (
{block.kind === 'code' && ( )} {block.kind === 'text' && ( View changes )} View Previous version View Next version Copy to clipboard
); } export const BlockActions = memo(PureBlockActions, (prevProps, nextProps) => { if (prevProps.block.status !== nextProps.block.status) return false; if (prevProps.currentVersionIndex !== nextProps.currentVersionIndex) return false; if (prevProps.isCurrentVersion !== nextProps.isCurrentVersion) return false; return true; });