mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
Checkpoint refactoring script out of just associated-record, for more general purpose
This commit is contained in:
@ -19,6 +19,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import Box from "@mui/material/Box";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
@ -31,7 +32,7 @@ import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||
|
||||
interface Props
|
||||
{
|
||||
logs: any;
|
||||
logs: QRecord[];
|
||||
}
|
||||
|
||||
ScriptLogsView.defaultProps = {
|
||||
@ -41,7 +42,7 @@ ScriptLogsView.defaultProps = {
|
||||
function ScriptLogsView({logs}: Props): JSX.Element
|
||||
{
|
||||
return (
|
||||
<TableContainer sx={{boxShadow: "none"}}>
|
||||
<TableContainer sx={{boxShadow: "none"}} className="scriptLogsView">
|
||||
<Table>
|
||||
<Box component="thead">
|
||||
<TableRow key="header">
|
||||
@ -55,29 +56,29 @@ function ScriptLogsView({logs}: Props): JSX.Element
|
||||
</Box>
|
||||
<TableBody>
|
||||
{
|
||||
logs.map((logRecord: any) =>
|
||||
logs?.map((logRecord: QRecord) =>
|
||||
{
|
||||
let logs = "";
|
||||
if (logRecord.values.scriptLogLine)
|
||||
if (logRecord.values.get("scriptLogLine"))
|
||||
{
|
||||
for (let i = 0; i < logRecord.values.scriptLogLine.length; i++)
|
||||
for (let i = 0; i < logRecord.values.get("scriptLogLine").length; i++)
|
||||
{
|
||||
console.log(" += " + i);
|
||||
logs += (logRecord.values.scriptLogLine[i].values.text + "\n");
|
||||
logs += (logRecord.values.get("scriptLogLine")[i].values.text + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow key={logRecord.values.id}>
|
||||
<DataTableBodyCell>{ValueUtils.formatDateTime(logRecord.values.startTimestamp)}</DataTableBodyCell>
|
||||
<DataTableBodyCell align="right">{logRecord.values.runTimeMillis?.toLocaleString()}</DataTableBodyCell>
|
||||
<TableRow key={logRecord.values.get("id")}>
|
||||
<DataTableBodyCell>{ValueUtils.formatDateTime(logRecord.values.get("startTimestamp"))}</DataTableBodyCell>
|
||||
<DataTableBodyCell align="right">{logRecord.values.get("runTimeMillis")?.toLocaleString()}</DataTableBodyCell>
|
||||
<DataTableBodyCell>
|
||||
<div style={{color: logRecord.values.hadError ? "red" : "auto"}}>{ValueUtils.formatBoolean(logRecord.values.hadError)}</div>
|
||||
<div style={{color: logRecord.values.get("hadError") ? "red" : "auto"}}>{ValueUtils.formatBoolean(logRecord.values.get("hadError"))}</div>
|
||||
</DataTableBodyCell>
|
||||
<DataTableBodyCell>{logRecord.values.input}</DataTableBodyCell>
|
||||
<DataTableBodyCell>{logRecord.values.get("input")}</DataTableBodyCell>
|
||||
<DataTableBodyCell>
|
||||
{logRecord.values.output}
|
||||
{logRecord.values.error}
|
||||
{logRecord.values.get("output")}
|
||||
{logRecord.values.get("error")}
|
||||
</DataTableBodyCell>
|
||||
<DataTableBodyCell>{logs}</DataTableBodyCell>
|
||||
</TableRow>
|
||||
|
@ -20,6 +20,8 @@
|
||||
*/
|
||||
|
||||
import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException";
|
||||
import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
|
||||
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
|
||||
@ -32,7 +34,6 @@ import Button from "@mui/material/Button";
|
||||
import Chip from "@mui/material/Chip";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Icon from "@mui/material/Icon";
|
||||
import List from "@mui/material/List";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import ListItemAvatar from "@mui/material/ListItemAvatar";
|
||||
@ -44,8 +45,12 @@ import Tabs from "@mui/material/Tabs";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import React, {useReducer, useState} from "react";
|
||||
import AceEditor from "react-ace";
|
||||
import {Link} from "react-router-dom";
|
||||
import TabPanel from "qqq/components/misc/TabPanel";
|
||||
import ScriptDocsForm from "qqq/components/scripts/ScriptDocsForm";
|
||||
import ScriptEditor, {ScriptEditorProps} from "qqq/components/scripts/ScriptEditor";
|
||||
import ScriptLogsView from "qqq/components/scripts/ScriptLogsView";
|
||||
import ScriptTestForm from "qqq/components/scripts/ScriptTestForm";
|
||||
import CustomWidthTooltip from "qqq/components/tooltips/CustomWidthTooltip";
|
||||
import {LoadingState} from "qqq/models/LoadingState";
|
||||
import DeveloperModeUtils from "qqq/utils/DeveloperModeUtils";
|
||||
@ -63,19 +68,33 @@ const qController = Client.getInstance();
|
||||
// Declaring props types for ViewForm
|
||||
interface Props
|
||||
{
|
||||
scriptId: number
|
||||
scriptId: number,
|
||||
associatedScriptTableName?: string,
|
||||
associatedScriptFieldName?: string,
|
||||
associatedScriptRecordId?: any,
|
||||
testInputFields?: QFieldMetaData[],
|
||||
testOutputFields?: QFieldMetaData[],
|
||||
}
|
||||
|
||||
ScriptViewer.defaultProps =
|
||||
{
|
||||
associatedScriptTableName: null,
|
||||
associatedScriptFieldName: null,
|
||||
associatedScriptRecordId: null,
|
||||
testInputFields: null,
|
||||
testOutputFields: null,
|
||||
};
|
||||
|
||||
export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
export default function ScriptViewer({scriptId, associatedScriptTableName, associatedScriptFieldName, associatedScriptRecordId, testInputFields, testOutputFields}: Props): JSX.Element
|
||||
{
|
||||
const [metaData, setMetaData] = useState(null as QInstance);
|
||||
const [scriptRecord, setScriptRecord] = useState(null as QRecord);
|
||||
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
|
||||
const [versionRecordList, setVersionRecordList] = useState(null as QRecord[]);
|
||||
const [selectedVersionRecord, setSelectedVersionRecord] = useState(null as QRecord);
|
||||
const [scriptLogs, setScriptLogs] = useState({} as any);
|
||||
const [scriptTypeRecord, setScriptTypeRecord] = useState(null as QRecord)
|
||||
const [testScriptDefinitionObject, setTestScriptDefinitionObject] = useState({} as any)
|
||||
const [currentVersionId , setCurrentVersionId] = useState(null as number);
|
||||
const [notFoundMessage, setNotFoundMessage] = useState(null);
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
@ -94,9 +113,24 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
{
|
||||
try
|
||||
{
|
||||
setMetaData(await qController.loadMetaData());
|
||||
|
||||
const scriptRecord = await qController.get("script", scriptId);
|
||||
setScriptRecord(scriptRecord);
|
||||
|
||||
setScriptTypeRecord(await qController.get("scriptType", scriptRecord.values.get("scriptTypeId")));
|
||||
|
||||
if(testInputFields !== null || testOutputFields !== null)
|
||||
{
|
||||
setTestScriptDefinitionObject({testInputFields: testInputFields, testOutputFields: testOutputFields});
|
||||
}
|
||||
else
|
||||
{
|
||||
setTestScriptDefinitionObject({testInputFields: [
|
||||
new QFieldMetaData({name: "recordPrimaryKeyList", label: "Record Primary Key List"})
|
||||
], testOutputFields: []})
|
||||
}
|
||||
|
||||
const criteria = [new QFilterCriteria("scriptId", QCriteriaOperator.EQUALS, [scriptId])];
|
||||
const orderBys = [new QFilterOrderBy("sequenceNo", false)];
|
||||
const filter = new QQueryFilter(criteria, orderBys);
|
||||
@ -181,11 +215,11 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
// fetch the full version
|
||||
setSelectedVersionRecord(version);
|
||||
setCurrentVersionId(version.values.get("id"));
|
||||
loadingSelectedVersion.setLoading();
|
||||
|
||||
const selectedVersion = await qController.get("scriptVersion", version.values.get("id"));
|
||||
// fetch the full version
|
||||
const selectedVersion = await qController.get("scriptRevision", version.values.get("id"));
|
||||
console.log("Fetched selectedVersion:");
|
||||
console.log(selectedVersion);
|
||||
setSelectedVersionRecord(selectedVersion);
|
||||
@ -236,11 +270,38 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
</List>;
|
||||
}
|
||||
|
||||
const getScriptLogs = (scriptRevisionId: number) =>
|
||||
{
|
||||
if(!scriptLogs[scriptRevisionId])
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
scriptLogs[scriptRevisionId] = await qController.query("scriptLog", new QQueryFilter([new QFilterCriteria("scriptRevisionId", QCriteriaOperator.EQUALS, [scriptRevisionId])]), 100, 0);
|
||||
setScriptLogs(scriptLogs);
|
||||
forceUpdate();
|
||||
})();
|
||||
return <Typography variant="body2" p={3}>Loading...</Typography>;
|
||||
}
|
||||
|
||||
const logs = scriptLogs[scriptRevisionId] as any[];
|
||||
if (logs === null || logs === undefined)
|
||||
{
|
||||
return <Typography variant="body2" p={3}>Loading...</Typography>;
|
||||
}
|
||||
|
||||
if (logs.length === 0)
|
||||
{
|
||||
return <Typography variant="body2" p={3}>No logs available for this version.</Typography>;
|
||||
}
|
||||
|
||||
return (<ScriptLogsView logs={logs} />);
|
||||
}
|
||||
|
||||
let editButtonTooltip = "";
|
||||
let editButtonText = "Create New Version";
|
||||
if (currentVersionId)
|
||||
{
|
||||
if (currentVersionId === selectedVersionRecord?.values?.get("id"))
|
||||
if (currentVersionId === scriptRecord?.values?.get("currentScriptRevisionId"))
|
||||
{
|
||||
editButtonTooltip = "If you make any changes to this script, a new version will be created when you hit Save.";
|
||||
editButtonText = "Edit";
|
||||
@ -253,6 +314,17 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
}
|
||||
}
|
||||
|
||||
function buildScriptLogFilter(scriptRevisionId: any)
|
||||
{
|
||||
return JSON.stringify(new QQueryFilter([new QFilterCriteria("scriptRevisionId", QCriteriaOperator.EQUALS, [scriptRevisionId])]));
|
||||
}
|
||||
|
||||
/*
|
||||
position: relative;
|
||||
left: -356px;
|
||||
width: calc(100% + 380px);
|
||||
*/
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
@ -288,13 +360,15 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
<Box display="flex" alignItems="center" justifyContent="space-between" gap={2} mt={-6}>
|
||||
<Typography variant="h5" p={2}></Typography>
|
||||
<Tabs
|
||||
sx={{mr: 1}}
|
||||
sx={{m: 1}}
|
||||
value={selectedTab}
|
||||
onChange={(event, newValue) => changeTab(newValue)}
|
||||
variant="standard"
|
||||
>
|
||||
<Tab label="Raw Data" id="simple-tab-0" aria-controls="simple-tabpanel-0" sx={{width: "150px"}} />
|
||||
<Tab label="Data Preview" id="simple-tab-1" aria-controls="simple-tabpanel-1" sx={{width: "150px"}} />
|
||||
<Tab label="Code" id="simple-tab-0" aria-controls="simple-tabpanel-0" sx={{width: "100px"}} />
|
||||
<Tab label="Logs" id="simple-tab-1" aria-controls="simple-tabpanel-1" sx={{width: "100px"}} />
|
||||
<Tab label="Test" id="simple-tab-1" aria-controls="simple-tabpanel-2" sx={{width: "100px"}} />
|
||||
<Tab label="Docs" id="simple-tab-1" aria-controls="simple-tabpanel-3" sx={{width: "100px"}} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
@ -314,7 +388,7 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
<Typography variant="h6">
|
||||
Version {selectedVersionRecord.values.get("sequenceNo")}
|
||||
{
|
||||
currentVersionId === selectedVersionRecord.values.get("id")
|
||||
currentVersionId === scriptRecord.values.get("currentScriptRevisionId")
|
||||
? (<> (Current)</>)
|
||||
: <></>
|
||||
}
|
||||
@ -350,7 +424,7 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabPanel>
|
||||
{/*
|
||||
|
||||
<TabPanel index={1} value={selectedTab}>
|
||||
<Grid container height="440px">
|
||||
<Grid item xs={4}>
|
||||
@ -360,17 +434,34 @@ export default function ScriptViewer({scriptId}: Props): JSX.Element
|
||||
{getVersionsList(versionRecordList, selectedVersionRecord)}
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
{
|
||||
selectedVersionRecord ? (
|
||||
<>
|
||||
<Box display="flex" alignItems="center" gap={2} pb={1} height="40px">
|
||||
<Typography variant="h6" pl={3}>Data Preview (Version {selectedVersionRecord?.values?.get("sequenceNo")})</Typography>
|
||||
<Typography variant="h6">Script Logs (Version {selectedVersionRecord?.values.get("sequenceNo")})</Typography>
|
||||
<Link style={{fontSize: "1rem"}} to={`${metaData.getTablePathByName("scriptLog")}?filter=${buildScriptLogFilter(selectedVersionRecord?.values.get("id"))}`}>View All</Link>
|
||||
</Box>
|
||||
<Box height="400px" overflow="auto" ml={1} fontSize="14px">
|
||||
{loadingSelectedVersion.isNotLoading() && selectedTab == 1 && selectedVersionRecord?.values?.get("data") && <ScriptPreview json={selectedVersionRecord?.values?.get("data")} /> }
|
||||
{loadingSelectedVersion.isLoadingSlow() && <Box pl={3}>Loading...</Box>}
|
||||
<Box height="400px" overflow="auto">
|
||||
{getScriptLogs(selectedVersionRecord.values.get("id"))}
|
||||
</Box>
|
||||
</>
|
||||
) : <Box>Select a version to view logs</Box>
|
||||
}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabPanel>
|
||||
*/}
|
||||
|
||||
<TabPanel index={2} value={selectedTab}>
|
||||
<Box sx={{height: "455px"}} px={2} pb={1}>
|
||||
<ScriptTestForm scriptDefinition={testScriptDefinitionObject} tableName={associatedScriptTableName} fieldName={associatedScriptFieldName} recordId={associatedScriptRecordId} code={selectedVersionRecord?.values.get("contents")} />
|
||||
</Box>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel index={3} value={selectedTab}>
|
||||
<Box sx={{height: "455px"}} px={2} pb={1}>
|
||||
<ScriptDocsForm helpText={scriptTypeRecord?.values.get("helpText")} exampleCode={scriptTypeRecord?.values.get("sampleCode")} />
|
||||
</Box>
|
||||
</TabPanel>
|
||||
</>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
@ -22,33 +22,18 @@
|
||||
import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException";
|
||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {Alert, Chip, Icon, ListItem, ListItemAvatar, Typography} from "@mui/material";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import {Alert, Typography} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Card from "@mui/material/Card";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import List from "@mui/material/List";
|
||||
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import Modal from "@mui/material/Modal";
|
||||
import Snackbar from "@mui/material/Snackbar";
|
||||
import Tab from "@mui/material/Tab";
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
import React, {useContext, useReducer, useState} from "react";
|
||||
import AceEditor from "react-ace";
|
||||
import {useParams} from "react-router-dom";
|
||||
import QContext from "QContext";
|
||||
import TabPanel from "qqq/components/misc/TabPanel";
|
||||
import AssociatedScriptEditor from "qqq/components/scripts/AssociatedScriptEditor";
|
||||
import ScriptDocsForm from "qqq/components/scripts/ScriptDocsForm";
|
||||
import ScriptLogsView from "qqq/components/scripts/ScriptLogsView";
|
||||
import ScriptTestForm from "qqq/components/scripts/ScriptTestForm";
|
||||
import CustomWidthTooltip from "qqq/components/tooltips/CustomWidthTooltip";
|
||||
import ScriptViewer from "qqq/components/widgets/misc/ScriptViewer";
|
||||
import BaseLayout from "qqq/layouts/BaseLayout";
|
||||
import DeveloperModeUtils from "qqq/utils/DeveloperModeUtils";
|
||||
import Client from "qqq/utils/qqq/Client";
|
||||
import ValueUtils from "qqq/utils/qqq/ValueUtils";
|
||||
|
||||
@ -60,7 +45,6 @@ import "ace-builds/src-noconflict/ext-language_tools";
|
||||
|
||||
const qController = Client.getInstance();
|
||||
|
||||
// Declaring props types for ViewForm
|
||||
interface Props
|
||||
{
|
||||
table?: QTableMetaData;
|
||||
@ -89,7 +73,6 @@ function RecordDeveloperView({table}: Props): JSX.Element
|
||||
const [viewingRevisions, setViewingRevisions] = useState({} as any);
|
||||
const [scriptLogs, setScriptLogs] = useState({} as any);
|
||||
|
||||
const [editingScript, setEditingScript] = useState(null as any);
|
||||
const [alertText, setAlertText] = useState(null as string);
|
||||
|
||||
const {setPageHeader} = useContext(QContext);
|
||||
@ -152,135 +135,13 @@ function RecordDeveloperView({table}: Props): JSX.Element
|
||||
})();
|
||||
}
|
||||
|
||||
const editScript = (fieldName: string, code: string, object: any) =>
|
||||
const createScript = async (fieldName: string) =>
|
||||
{
|
||||
const editingScript = {} as any;
|
||||
editingScript.fieldName = fieldName;
|
||||
editingScript.titlePrefix = code ? "Editing Script" : "Creating New Script";
|
||||
editingScript.code = code;
|
||||
editingScript.scriptDefinitionObject = object;
|
||||
setEditingScript(editingScript);
|
||||
};
|
||||
|
||||
const closeEditingScript = (event: object, reason: string, alert: string = null) =>
|
||||
{
|
||||
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (reason === "saved")
|
||||
{
|
||||
setAsyncLoadInited(false);
|
||||
setAssociatedScripts([]);
|
||||
viewingRevisions[editingScript.fieldName] = null;
|
||||
setViewingRevisions(viewingRevisions);
|
||||
forceUpdate();
|
||||
}
|
||||
|
||||
if (alert)
|
||||
{
|
||||
setAlertText(alert);
|
||||
}
|
||||
|
||||
setEditingScript(null);
|
||||
};
|
||||
|
||||
const changeTab = (newValue: number, fieldName: string) =>
|
||||
{
|
||||
selectedTabs[fieldName] = newValue;
|
||||
setSelectedTabs(selectedTabs);
|
||||
const rs = await qController.storeRecordAssociatedScript(tableName, id, fieldName, "// Edit this new script to define its code.", "Initial version");
|
||||
record.values.set(fieldName, rs.scriptId);
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
const selectRevision = (fieldName: string, revisionId: number) =>
|
||||
{
|
||||
viewingRevisions[fieldName] = revisionId;
|
||||
setViewingRevisions(viewingRevisions);
|
||||
|
||||
scriptLogs[revisionId] = null;
|
||||
setScriptLogs(scriptLogs);
|
||||
|
||||
loadRevisionLogs(fieldName, revisionId);
|
||||
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
const loadRevisionLogs = (fieldName: string, revisionId: number) =>
|
||||
{
|
||||
(async () =>
|
||||
{
|
||||
const rs = await qController.getRecordAssociatedScriptLogs(tableName, id, fieldName, revisionId);
|
||||
scriptLogs[revisionId] = [];
|
||||
if (rs["scriptLogRecords"])
|
||||
{
|
||||
scriptLogs[revisionId] = rs["scriptLogRecords"];
|
||||
}
|
||||
console.log("Script logs:");
|
||||
console.log(scriptLogs[revisionId]);
|
||||
setScriptLogs(scriptLogs);
|
||||
forceUpdate();
|
||||
})();
|
||||
};
|
||||
|
||||
function getRevisionsList(scriptRevisions: any, fieldName: any, currentScriptRevisionId: any)
|
||||
{
|
||||
return <List sx={{pl: 3, height: "400px", overflow: "auto"}}>
|
||||
{
|
||||
scriptRevisions ? <></> :
|
||||
<Typography variant="body2">
|
||||
There are not any versions of this script.
|
||||
</Typography>
|
||||
}
|
||||
{
|
||||
scriptRevisions?.map((revision: any) => (
|
||||
<React.Fragment key={revision.values.id}>
|
||||
<ListItem sx={{p: 1}} alignItems="flex-start" selected={viewingRevisions[fieldName] == revision.values.id} onClick={(event) => selectRevision(fieldName, revision.values.id)}>
|
||||
<ListItemAvatar>
|
||||
<Avatar sx={{bgcolor: DeveloperModeUtils.revToColor(fieldName, id, revision.values.sequenceNo)}}>{`${revision.values.sequenceNo}`}</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primaryTypographyProps={{fontSize: "1rem"}}
|
||||
secondaryTypographyProps={{fontSize: ".85rem"}}
|
||||
primary={
|
||||
<div style={{whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis"}} title={revision.values.commitMessage}>
|
||||
{revision.values.id == currentScriptRevisionId && <Chip label="CURRENT" color="success" variant="outlined" size="small" sx={{mr: 1, fontSize: "0.75rem"}} />}
|
||||
{revision.values.commitMessage}
|
||||
</div>
|
||||
}
|
||||
secondary={
|
||||
<>
|
||||
{ValueUtils.formatDateTime(revision.values.createDate)}
|
||||
<br />
|
||||
{revision.values.author}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<ListItemIcon sx={{minWidth: "auto", px: 1}}><Icon>settings</Icon></ListItemIcon>
|
||||
</ListItem>
|
||||
<Divider sx={{my: 0.5}} variant="inset" component="li" />
|
||||
</React.Fragment>
|
||||
))
|
||||
}
|
||||
</List>;
|
||||
}
|
||||
|
||||
function getScriptLogs(revisionId: number)
|
||||
{
|
||||
const logs = scriptLogs[revisionId] as any[];
|
||||
if (logs === null || logs === undefined)
|
||||
{
|
||||
return <Typography variant="body2" p={3}>Loading...</Typography>;
|
||||
}
|
||||
|
||||
if (logs.length === 0)
|
||||
{
|
||||
return <Typography variant="body2" p={3}>No logs available for this version.</Typography>;
|
||||
}
|
||||
|
||||
return (<ScriptLogsView logs={logs} />);
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseLayout>
|
||||
<Box>
|
||||
@ -289,8 +150,7 @@ function RecordDeveloperView({table}: Props): JSX.Element
|
||||
<Box mb={3}>
|
||||
{
|
||||
notFoundMessage
|
||||
?
|
||||
<Box>{notFoundMessage}</Box>
|
||||
? <Box>{notFoundMessage}</Box>
|
||||
:
|
||||
<Box pb={3}>
|
||||
{
|
||||
@ -323,18 +183,33 @@ 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 = recordJSONString ? recordJSONObject[fieldName] : null;
|
||||
let scriptId = record?.values.get(fieldName);
|
||||
return (
|
||||
<div key={fieldName}>
|
||||
<Card sx={{mb: 3}}>
|
||||
<Typography variant="h5" p={2}>{field?.label}</Typography>
|
||||
<Typography variant="h6" p={2} pl={3} pb={1}>{field?.label}</Typography>
|
||||
|
||||
<Box display="flex" alignItems="center" justifyContent="space-between" gap={2}>
|
||||
{scriptId ?
|
||||
<ScriptViewer scriptId={scriptId}></ScriptViewer>
|
||||
: <>No script here yet. {/* todo! */}</>
|
||||
<ScriptViewer
|
||||
scriptId={scriptId}
|
||||
associatedScriptTableName={tableName}
|
||||
associatedScriptFieldName={fieldName}
|
||||
associatedScriptRecordId={id}
|
||||
testInputFields={object.testInputFields}
|
||||
testOutputFields={object.testOutputFields}
|
||||
></ScriptViewer>
|
||||
: <>
|
||||
<Box p={3} fontSize={"1rem"}>
|
||||
No script has been created in this field for this record at this time.
|
||||
</Box>
|
||||
<Box>
|
||||
<Button onClick={() => createScript(fieldName)}>Create Script</Button>
|
||||
</Box>
|
||||
</>
|
||||
}
|
||||
</Box>
|
||||
</Card>
|
||||
@ -343,171 +218,8 @@ function RecordDeveloperView({table}: Props): JSX.Element
|
||||
})
|
||||
}
|
||||
|
||||
{/*
|
||||
associatedScripts && associatedScripts.map((object) =>
|
||||
{
|
||||
let fieldName = object.associatedScript?.fieldName;
|
||||
let field = tableMetaData.fields.get(fieldName);
|
||||
|
||||
let currentScriptRevisionId = object.script?.values?.currentScriptRevisionId;
|
||||
|
||||
if (!selectedTabs[fieldName])
|
||||
{
|
||||
selectedTabs[fieldName] = 0;
|
||||
}
|
||||
|
||||
if (!viewingRevisions[fieldName] || viewingRevisions[fieldName] === -1)
|
||||
{
|
||||
console.log(`Defaulting revision for ${fieldName} to ${currentScriptRevisionId}`);
|
||||
viewingRevisions[fieldName] = currentScriptRevisionId;
|
||||
|
||||
if (!scriptLogs[currentScriptRevisionId])
|
||||
{
|
||||
loadRevisionLogs(fieldName, currentScriptRevisionId);
|
||||
}
|
||||
}
|
||||
|
||||
const viewingRevisionArray = object.scriptRevisions?.filter((rev: any) => rev?.values?.id === viewingRevisions[fieldName]);
|
||||
const code = viewingRevisionArray?.length > 0 ? viewingRevisionArray[0].values.contents : "";
|
||||
const viewingSequenceNo = viewingRevisionArray?.length > 0 ? viewingRevisionArray[0].values.sequenceNo : "";
|
||||
|
||||
let editButtonTooltip = "";
|
||||
let editButtonText = "Create New Script";
|
||||
if (currentScriptRevisionId)
|
||||
{
|
||||
if (currentScriptRevisionId === viewingRevisions[fieldName])
|
||||
{
|
||||
editButtonTooltip = "If you make any changes to this script, a new version will be created when you hit Save.";
|
||||
editButtonText = "Edit";
|
||||
}
|
||||
else
|
||||
{
|
||||
editButtonTooltip = "If you want to make this previous Version active, bring up the Edit window, make any changes " +
|
||||
"to the old Version if they are needed, then click Save. A new Version will be created, and set as Current.";
|
||||
editButtonText = "Edit and Activate";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Card key={fieldName} id={`associatedScript.${fieldName}`} sx={{mb: 3}}>
|
||||
|
||||
<Box display="flex" alignItems="center" justifyContent="space-between" gap={2}>
|
||||
<Typography variant="h5" p={2}>{field?.label}</Typography>
|
||||
<Tabs
|
||||
sx={{mr: 1}}
|
||||
value={selectedTabs[fieldName]}
|
||||
onChange={(event, newValue) => changeTab(newValue, fieldName)}
|
||||
variant="standard"
|
||||
>
|
||||
<Tab label="Code" id="simple-tab-0" aria-controls="simple-tabpanel-0" sx={{width: "100px"}} />
|
||||
<Tab label="Logs" id="simple-tab-1" aria-controls="simple-tabpanel-1" sx={{width: "100px"}} />
|
||||
<Tab label="Test" id="simple-tab-2" aria-controls="simple-tabpanel-2" sx={{width: "100px"}} />
|
||||
<Tab label="Docs" id="simple-tab-3" aria-controls="simple-tabpanel-3" sx={{width: "100px"}} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<TabPanel index={0} value={selectedTabs[fieldName]}>
|
||||
<Grid container>
|
||||
<Grid item xs={4}>
|
||||
<Box display="flex" alignItems="center" gap={2} pb={1} height="40px">
|
||||
<Typography variant="h6" pl={3}>Versions</Typography>
|
||||
</Box>
|
||||
{getRevisionsList(object.scriptRevisions, fieldName, currentScriptRevisionId)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={8}>
|
||||
<Box display="flex" alignItems="center" gap={2} pb={1} height="40px">
|
||||
{
|
||||
currentScriptRevisionId &&
|
||||
<Typography variant="h6">
|
||||
{
|
||||
currentScriptRevisionId === viewingRevisions[fieldName]
|
||||
? (<>Current Version ({viewingSequenceNo})</>)
|
||||
: (<>Version {viewingSequenceNo}</>)
|
||||
}
|
||||
</Typography>
|
||||
}
|
||||
<CustomWidthTooltip title={editButtonTooltip}>
|
||||
<Button sx={{py: 0}} onClick={() => editScript(fieldName, code, object)}>
|
||||
{editButtonText}
|
||||
</Button>
|
||||
</CustomWidthTooltip>
|
||||
</Box>
|
||||
{
|
||||
code ? (
|
||||
<>
|
||||
<AceEditor
|
||||
mode="javascript"
|
||||
theme="github"
|
||||
name={`view-${fieldName}`}
|
||||
readOnly
|
||||
highlightActiveLine={false}
|
||||
editorProps={{$blockScrolling: true}}
|
||||
width="100%"
|
||||
height="400px"
|
||||
value={code}
|
||||
/>
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabPanel>
|
||||
<TabPanel index={1} value={selectedTabs[fieldName]}>
|
||||
<Grid container height="440px">
|
||||
<Grid item xs={4}>
|
||||
<Box display="flex" alignItems="center" gap={2} pb={1} height="40px">
|
||||
<Typography variant="h6" pl={3}>Versions</Typography>
|
||||
</Box>
|
||||
{getRevisionsList(object.scriptRevisions, fieldName, currentScriptRevisionId)}
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
<Box display="flex" alignItems="center" gap={2} pb={1} height="40px">
|
||||
<Typography variant="h6" pl={3}>Script Logs (Version {viewingSequenceNo})</Typography>
|
||||
</Box>
|
||||
<Box height="400px" overflow="auto">
|
||||
{getScriptLogs(viewingRevisions[fieldName])}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabPanel>
|
||||
<TabPanel index={2} value={selectedTabs[fieldName]}>
|
||||
<Box sx={{height: "455px"}} px={2} pb={1}>
|
||||
<ScriptTestForm scriptDefinition={object} tableName={tableName} fieldName={fieldName} recordId={id} code={code} />
|
||||
</Box>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel index={3} value={selectedTabs[fieldName]}>
|
||||
<Box sx={{height: "455px"}} px={2} pb={1}>
|
||||
<ScriptDocsForm helpText={object.scriptType.values.helpText} exampleCode={object.scriptType.values.sampleCode} />
|
||||
</Box>
|
||||
</TabPanel>
|
||||
</Card>
|
||||
);
|
||||
})
|
||||
*/}
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{
|
||||
editingScript &&
|
||||
<Modal open={editingScript as boolean} onClose={(event, reason) => closeEditingScript(event, reason)}>
|
||||
<AssociatedScriptEditor
|
||||
scriptDefinition={editingScript.scriptDefinitionObject}
|
||||
tableName={tableName}
|
||||
primaryKey={id}
|
||||
fieldName={editingScript.fieldName}
|
||||
titlePrefix={editingScript.titlePrefix}
|
||||
recordLabel={record.recordLabel}
|
||||
scriptName={tableMetaData.fields.get(editingScript.fieldName).label}
|
||||
code={editingScript.code}
|
||||
closeCallback={closeEditingScript}
|
||||
/>
|
||||
</Modal>
|
||||
}
|
||||
|
||||
</Box>
|
||||
}
|
||||
</Box>
|
||||
|
@ -339,6 +339,12 @@ input[type="search"]::-webkit-search-results-decoration { display: none; }
|
||||
border-right: 0.0625rem solid rgb(222, 226, 230);
|
||||
}
|
||||
|
||||
.scriptLogsView TD,
|
||||
.scriptLogsView TH
|
||||
{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.fieldLabel
|
||||
{
|
||||
color: rgb(52, 71, 103);
|
||||
|
Reference in New Issue
Block a user