/*
* 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