From dff7c972bf87f35602cadffce8df2ca833a0162b Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 9 Mar 2023 18:19:02 -0600 Subject: [PATCH] Further implementation of script testing (e.g.,record-type scripts working); add logs to test script output --- src/qqq/components/scripts/ScriptEditor.tsx | 2 +- src/qqq/components/scripts/ScriptLogsView.tsx | 1 - src/qqq/components/scripts/ScriptTestForm.tsx | 132 +++++++++++++++--- .../components/widgets/misc/DataBagViewer.tsx | 2 +- .../components/widgets/misc/ScriptViewer.tsx | 2 +- .../records/view/RecordDeveloperView.tsx | 1 - src/qqq/styles/qqq-override-styles.css | 14 +- src/qqq/utils/qqq/ValueUtils.tsx | 10 ++ 8 files changed, 138 insertions(+), 26 deletions(-) diff --git a/src/qqq/components/scripts/ScriptEditor.tsx b/src/qqq/components/scripts/ScriptEditor.tsx index c703d49..ecd0014 100644 --- a/src/qqq/components/scripts/ScriptEditor.tsx +++ b/src/qqq/components/scripts/ScriptEditor.tsx @@ -192,7 +192,7 @@ function ScriptEditor({title, scriptId, contents, closeCallback, tableName, fiel openTool && { - openTool == "test" && + openTool == "test" && } { openTool == "docs" && diff --git a/src/qqq/components/scripts/ScriptLogsView.tsx b/src/qqq/components/scripts/ScriptLogsView.tsx index 43d9bc0..07fc9e0 100644 --- a/src/qqq/components/scripts/ScriptLogsView.tsx +++ b/src/qqq/components/scripts/ScriptLogsView.tsx @@ -63,7 +63,6 @@ function ScriptLogsView({logs}: Props): JSX.Element { for (let i = 0; i < logRecord.values.get("scriptLogLine").length; i++) { - console.log(" += " + i); logs += (logRecord.values.get("scriptLogLine")[i].values.text + "\n"); } } diff --git a/src/qqq/components/scripts/ScriptTestForm.tsx b/src/qqq/components/scripts/ScriptTestForm.tsx index 06d1b63..551bc65 100644 --- a/src/qqq/components/scripts/ScriptTestForm.tsx +++ b/src/qqq/components/scripts/ScriptTestForm.tsx @@ -19,15 +19,26 @@ * 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"; @@ -39,6 +50,7 @@ interface AssociatedScriptDefinition interface Props { + scriptId: number; scriptDefinition: AssociatedScriptDefinition; tableName: string; fieldName: string; @@ -52,10 +64,11 @@ ScriptTestForm.defaultProps = { const qController = Client.getInstance(); -function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code}: Props): JSX.Element +function ScriptTestForm({scriptId, scriptDefinition, tableName, fieldName, recordId, code}: Props): 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); @@ -68,7 +81,7 @@ function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code} { scriptDefinition.testInputFields.forEach((field: QFieldMetaData) => { - testInputValues[field.name] = ""; + testInputValues[field.name] = field.defaultValue ?? ""; }); } @@ -84,27 +97,81 @@ function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code} } setTestOutputValues({}); + setLogLines([]); setTestException(null); (async () => { - const output = await qController.testScript(tableName, recordId, fieldName, code, inputValues); - console.log("got output:") - console.log(output); - console.log(Object.keys(output)); - setTestOutputValues(output.outputObject); - if(output.exception) + try { - setTestException(output.exception.message) - console.log(`set test exception to ${output.exception.message}`); + 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("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) + { + setTestException(output.exception.message) + console.log(`set test exception to ${output.exception.message}`); + } + + if(output.scriptLogLines && output.scriptLogLines.length) + { + const scriptLogLines = []; + for(var i = 0; i { testInputValues[fieldName] = newValue; @@ -112,10 +179,8 @@ function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code} setTestInputValues(JSON.parse(JSON.stringify(testInputValues))); } - // console.log(testInputValues); - return ( - + @@ -135,6 +200,8 @@ function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code} { handleInputChange(field.name, event.target.value); }} + multiline={field.type == QFieldType.TEXT} + maxRows={field.type == QFieldType.TEXT ? 5 : 1} fullWidth sx={{mb: 2}} />); @@ -160,11 +227,9 @@ function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code} } { - scriptDefinition.testOutputFields && testOutputValues && scriptDefinition.testOutputFields.map((f: any) => + scriptDefinition.testOutputFields && scriptDefinition.testOutputFields.map((f: any) => { const field = new QFieldMetaData(f); - console.log(field.name); - console.log(testOutputValues[field.name]); return ( @@ -177,6 +242,33 @@ function ScriptTestForm({scriptDefinition, tableName, fieldName, recordId, code} ); }) } + { + logLines && logLines.length ? + <> + Test Log Lines + + + + + Timestamp + Log Line + + + + { + logLines.map((logLine: any, i: number) => + ( + + {ValueUtils.formatTime(logLine["timestamp"])} + {logLine["text"]} + + )) + } + +
+
+ : <> + }
diff --git a/src/qqq/components/widgets/misc/DataBagViewer.tsx b/src/qqq/components/widgets/misc/DataBagViewer.tsx index cdcc604..fbe47cb 100644 --- a/src/qqq/components/widgets/misc/DataBagViewer.tsx +++ b/src/qqq/components/widgets/misc/DataBagViewer.tsx @@ -289,7 +289,7 @@ export default function DataBagViewer({dataBagId}: Props): JSX.Element changeTab(newValue)} variant="standard" diff --git a/src/qqq/components/widgets/misc/ScriptViewer.tsx b/src/qqq/components/widgets/misc/ScriptViewer.tsx index e877803..28c9d20 100644 --- a/src/qqq/components/widgets/misc/ScriptViewer.tsx +++ b/src/qqq/components/widgets/misc/ScriptViewer.tsx @@ -458,7 +458,7 @@ export default function ScriptViewer({scriptId, associatedScriptTableName, assoc - + diff --git a/src/qqq/pages/records/view/RecordDeveloperView.tsx b/src/qqq/pages/records/view/RecordDeveloperView.tsx index 7f32f7b..f0152e8 100644 --- a/src/qqq/pages/records/view/RecordDeveloperView.tsx +++ b/src/qqq/pages/records/view/RecordDeveloperView.tsx @@ -183,7 +183,6 @@ function RecordDeveloperView({table}: Props): JSX.Element { associatedScripts && associatedScripts.map((object) => { - console.log(object); let fieldName = object.associatedScript?.fieldName; let field = tableMetaData.fields.get(fieldName); let scriptId = record?.values.get(fieldName); diff --git a/src/qqq/styles/qqq-override-styles.css b/src/qqq/styles/qqq-override-styles.css index 71ee9cb..0b5585c 100644 --- a/src/qqq/styles/qqq-override-styles.css +++ b/src/qqq/styles/qqq-override-styles.css @@ -366,4 +366,16 @@ input[type="search"]::-webkit-search-results-decoration { display: none; } top: 30px !important; height: calc(100vh - 60px) !important; z-index: 1300 !important; -} \ No newline at end of file +} + +.scriptTestForm TEXTAREA +{ + resize: vertical !important; +} + +.scriptTestForm .scriptLogLines TD, +.scriptTestForm .scriptLogLines TH +{ + padding-left: 0; + padding-right: 0; +} diff --git a/src/qqq/utils/qqq/ValueUtils.tsx b/src/qqq/utils/qqq/ValueUtils.tsx index 1ab8086..65e5b08 100644 --- a/src/qqq/utils/qqq/ValueUtils.tsx +++ b/src/qqq/utils/qqq/ValueUtils.tsx @@ -253,6 +253,16 @@ class ValueUtils return (`${date.toString("yyyy-MM-dd hh:mm:ss")} ${date.getHours() < 12 ? "AM" : "PM"} ${date.getTimezone()}`); } + public static formatTime(date: Date) + { + if(!(date instanceof Date)) + { + date = new Date(date) + } + // @ts-ignore + return (`${date.toString("hh:mm:ss")} ${date.getHours() < 12 ? "AM" : "PM"} ${date.getTimezone()}`); + } + public static formatDateTimeISO8601(date: Date) { if(!(date instanceof Date))