/* * QQQ - Low-code Application Framework for Engineers. * Copyright (C) 2021-2022. Kingsrook, LLC * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States * contact@kingsrook.com * https://github.com/Kingsrook/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException"; import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData"; import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType"; import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete"; import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError"; import {Typography} from "@mui/material"; import Box from "@mui/material/Box"; import Button from "@mui/material/Button"; import Card from "@mui/material/Card"; import Grid from "@mui/material/Grid"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableContainer from "@mui/material/TableContainer"; import TableRow from "@mui/material/TableRow"; import TextField from "@mui/material/TextField"; import FormData from "form-data"; import React, {useState} from "react"; import MDTypography from "qqq/components/legacy/MDTypography"; import DataTableBodyCell from "qqq/components/widgets/tables/cells/DataTableBodyCell"; import DataTableHeadCell from "qqq/components/widgets/tables/cells/DataTableHeadCell"; import Client from "qqq/utils/qqq/Client"; import ValueUtils from "qqq/utils/qqq/ValueUtils"; interface AssociatedScriptDefinition { testInputFields: QFieldMetaData[]; testOutputFields: QFieldMetaData[]; } export interface ScriptTestFormProps { scriptId: number; scriptDefinition: AssociatedScriptDefinition; tableName: string; fieldName: string; recordId: any; code: string; apiName: string; apiVersion: string; } const qController = Client.getInstance(); function ScriptTestForm({scriptId, scriptDefinition, tableName, fieldName, recordId, code, apiName, apiVersion}: ScriptTestFormProps): JSX.Element { const [testInputValues, setTestInputValues] = useState({} as any); const [testOutputValues, setTestOutputValues] = useState({} as any); const [logLines, setLogLines] = useState([] as any[]) const [testException, setTestException] = useState(null as string) const [firstRender, setFirstRender] = useState(true); if(firstRender) { scriptDefinition.testInputFields.forEach((field: QFieldMetaData) => { testInputValues[field.name] = field.defaultValue ?? ""; }); } const buildFullExceptionMessage = (exception: any): string => { return (exception.message + (exception.cause ? "\ncaused by: " + buildFullExceptionMessage(exception.cause) : "")); }; const testScript = () => { const inputValues = new Map(); if (scriptDefinition.testInputFields) { scriptDefinition.testInputFields.forEach((field: QFieldMetaData) => { inputValues.set(field.name, testInputValues[field.name]); }); } setTestOutputValues({}); setLogLines([]); setTestException(null); (async () => { try { let output; if(tableName && recordId && fieldName) { ///////////////////////////////////////////////////////////////// // associated record scripts - run this way (at least for now) // ///////////////////////////////////////////////////////////////// output = await qController.testScript(tableName, recordId, fieldName, code, inputValues); } else { const formData = new FormData(); formData.append("scriptId", scriptId); formData.append("apiName", apiName); formData.append("apiVersion", apiVersion); formData.append("code", code); for(let fieldName of inputValues.keys()) { formData.append(fieldName, inputValues.get(fieldName)); } const processResult = await qController.processRun("testScript", formData, null, true); if (processResult instanceof QJobError) { const jobError = processResult as QJobError setTestException(jobError.userFacingError ?? jobError.error) return; } const jobComplete = processResult as QJobComplete output = jobComplete.values; } console.log("got output:") console.log(output); console.log(Object.keys(output)); setTestOutputValues(output.outputObject ?? {}); if(output.exception) { const exceptionMessage = buildFullExceptionMessage(output.exception); setTestException(exceptionMessage) } if(output.scriptLogLines && output.scriptLogLines.length) { const scriptLogLines = []; for(var i = 0; i { testInputValues[fieldName] = newValue; console.log(`Setting ${fieldName} = ${newValue}`); setTestInputValues(JSON.parse(JSON.stringify(testInputValues))); } return ( Test Input { scriptDefinition.testInputFields && testInputValues && scriptDefinition.testInputFields.map((field: QFieldMetaData) => { return ( { handleInputChange(field.name, event.target.value); }} multiline={field.type == QFieldType.TEXT} maxRows={field.type == QFieldType.TEXT ? 5 : 1} fullWidth sx={{mb: 2}} />); }) }
Test Output { testException && {testException} } { scriptDefinition.testOutputFields && scriptDefinition.testOutputFields.map((f: any) => { const field = new QFieldMetaData(f); return ( {field.label}: {ValueUtils.getValueForDisplay(field, testOutputValues[field.name], testOutputValues[field.name], "view")} ); }) } { logLines && logLines.length ? <> Test Log Lines Timestamp Log Line { logLines.map((logLine: any, i: number) => ( {ValueUtils.formatTime(logLine["timestamp"])} {logLine["text"]} )) }
: <> }
); } export default ScriptTestForm;