import { Play, X } from "phosphor-react"; import { HTMLInputTypeAttribute, useCallback, useEffect, useState, } from "react"; import state, { IAccount, IFile, ILog } from "../../state"; import Button from "../Button"; import Box from "../Box"; import Input from "../Input"; import Stack from "../Stack"; import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription, DialogClose, } from "../Dialog"; import Flex from "../Flex"; import { useSnapshot } from "valtio"; import Select from "../Select"; import Text from "../Text"; import { saveFile } from "../../state/actions/saveFile"; import { getTags } from "../../utils/comment-parser"; const generateHtmlTemplate = (code: string, data?: Record) => { let processString: string | undefined; const process = { env: { NODE_ENV: "production" } } as any; if (data) { Object.keys(data).forEach(key => { process.env[key] = data[key]; }); } processString = JSON.stringify(process); return ` `; }; type Fields = Record< string, { name: string; value: string; type?: "Account" | `Account.${keyof IAccount}` | HTMLInputTypeAttribute; description?: string; } >; const RunScript: React.FC<{ file: IFile }> = ({ file: { content, name } }) => { const snap = useSnapshot(state); const [templateError, setTemplateError] = useState(""); const [fields, setFields] = useState({}); const [iFrameCode, setIframeCode] = useState(""); const [isDialogOpen, setIsDialogOpen] = useState(false); const getFields = useCallback(() => { try { const inputTags = ["input", "param", "arg", "argument"]; const tags = getTags(content) .filter(tag => inputTags.includes(tag.tag)) .filter(tag => !!tag.name); let _fields = tags.map(tag => ({ name: tag.name, value: tag.default || "", type: tag.type, description: tag.description, })); const fields: Fields = _fields.reduce((acc, field) => { acc[field.name] = field; return acc; }, {} as Fields); setTemplateError(""); // TODO return fields; } catch (err) { console.log(err); setTemplateError("Could not parse template"); return undefined; } }, [content]); const runScript = () => { try { let data: any = {}; Object.keys(fields).forEach(key => { data[key] = fields[key].value; }); const template = generateHtmlTemplate(content, data); setIframeCode(template); state.scriptLogs = [ ...snap.scriptLogs, { type: "success", message: "Started running..." }, ]; } catch (err) { state.scriptLogs = [ ...snap.scriptLogs, // @ts-expect-error { type: "error", message: err?.message || "Could not parse template" }, ]; } }; useEffect(() => { const handleEvent = (e: any) => { if (e.data.type === "log" || e.data.type === "error") { const data: ILog[] = e.data.args.map((msg: any) => ({ type: e.data.type, message: typeof msg === "string" ? msg : JSON.stringify(msg, null, 2), })); state.scriptLogs = [...snap.scriptLogs, ...data]; } }; window.addEventListener("message", handleEvent); return () => window.removeEventListener("message", handleEvent); }, [snap.scriptLogs]); useEffect(() => { const defaultFields = getFields() || {}; setFields(defaultFields); }, [content, setFields, getFields]); const accOptions = snap.accounts?.map(acc => ({ ...acc, label: acc.name, value: acc.address, })); return ( <> Run {name} script You are about to run scripts provided by the developer of the hook, make sure you trust the author before you continue. {templateError && ( (TODO)Error occured while parsing JSDOC tags, modify script and try again! )} {Object.keys(fields).length > 0 && ( Fill in the following parameters to run the script. )} {Object.keys(fields).map(key => { const { name, value, type, description } = fields[key]; const isAccount = type?.startsWith("Account"); const isAccountSecret = type === "Account.secret"; const accountField = (isAccount && type?.split(".")[1]) || "address"; return ( {isAccount ? ( { setFields({ ...fields, [key]: { ...fields[key], value: e.target.value }, }); }} /> )} ); })} {iFrameCode && (