mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 11:24:35 +00:00
feat(log): use improved log for SAS run time only
This commit is contained in:
@@ -23,6 +23,7 @@ import LogTabWithIcons from './internal/components/log/logTabWithIcons'
|
||||
import { usePrompt } from '../../utils/hooks'
|
||||
import { getLanguageFromExtension } from './internal/helper'
|
||||
import useEditor from './internal/hooks/useEditor'
|
||||
import { RunTimeType } from '../../context/appContext'
|
||||
|
||||
const StyledTabPanel = styled(TabPanel)(() => ({
|
||||
padding: '10px'
|
||||
@@ -110,7 +111,11 @@ const SASjsEditor = ({
|
||||
/>
|
||||
)
|
||||
|
||||
const logWithErrorsOrWarnings = log?.errors.length || log?.warnings.length
|
||||
// INFO: variable indicating if selected run type is SAS if there are any errors or warnings in the log
|
||||
const logWithErrorsOrWarnings =
|
||||
selectedRunTime === RunTimeType.SAS &&
|
||||
log &&
|
||||
(log?.errors.length !== 0 || log?.warnings.length !== 0)
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%', typography: 'body1', marginTop: '50px' }}>
|
||||
@@ -155,6 +160,11 @@ const SASjsEditor = ({
|
||||
icon={
|
||||
logWithErrorsOrWarnings ? <LogTabWithIcons log={log} /> : ''
|
||||
}
|
||||
onClick={() => {
|
||||
const logWrapper = document.querySelector(`#logWrapper`)
|
||||
|
||||
if (logWrapper) logWrapper.scrollTop = 0
|
||||
}}
|
||||
/>
|
||||
<StyledTab
|
||||
label={
|
||||
@@ -205,7 +215,9 @@ const SASjsEditor = ({
|
||||
</Paper>
|
||||
</StyledTabPanel>
|
||||
<StyledTabPanel value="log">
|
||||
{log && <LogComponent log={log} />}
|
||||
{log && (
|
||||
<LogComponent log={log} selectedRunTime={selectedRunTime} />
|
||||
)}
|
||||
</StyledTabPanel>
|
||||
<StyledTabPanel value="webout">
|
||||
<div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ListItemText } from '@mui/material'
|
||||
import { makeStyles } from '@mui/styles'
|
||||
import Highlight from 'react-highlight'
|
||||
import { LogObject } from '../../../../../utils'
|
||||
import { RunTimeType } from '../../../../../context/appContext'
|
||||
|
||||
const useStyles: any = makeStyles((theme: any) => ({
|
||||
expansionDescription: {
|
||||
@@ -30,10 +31,11 @@ const useStyles: any = makeStyles((theme: any) => ({
|
||||
|
||||
interface LogComponentProps {
|
||||
log: LogObject
|
||||
selectedRunTime: RunTimeType
|
||||
}
|
||||
|
||||
const LogComponent = (props: LogComponentProps) => {
|
||||
const { log } = props
|
||||
const { log, selectedRunTime } = props
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
@@ -63,77 +65,91 @@ const LogComponent = (props: LogComponentProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
id="logWrapper"
|
||||
style={{ overflowY: 'auto', maxHeight: 'calc(100vh - 130px)' }}
|
||||
>
|
||||
<div style={{ backgroundColor: 'white' }}>
|
||||
<>
|
||||
{selectedRunTime === RunTimeType.SAS ? (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: 10
|
||||
}}
|
||||
></div>
|
||||
<div style={{ paddingBottom: 10 }}>
|
||||
<TreeView
|
||||
defaultCollapseIcon={<ExpandMore />}
|
||||
defaultExpandIcon={<ChevronRight />}
|
||||
>
|
||||
{log?.errors.length && (
|
||||
<TreeItem
|
||||
nodeId="errors"
|
||||
label={
|
||||
<Typography color="error">
|
||||
{`Errors (${log.errors.length})`}
|
||||
</Typography>
|
||||
}
|
||||
id="logWrapper"
|
||||
style={{ overflowY: 'auto', maxHeight: 'calc(100vh - 130px)' }}
|
||||
>
|
||||
<div style={{ backgroundColor: 'white' }}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
gap: 10
|
||||
}}
|
||||
></div>
|
||||
<div style={{ paddingBottom: 10 }}>
|
||||
<TreeView
|
||||
defaultCollapseIcon={<ExpandMore />}
|
||||
defaultExpandIcon={<ChevronRight />}
|
||||
>
|
||||
{log.errors &&
|
||||
log.errors.map((error, ind) => (
|
||||
<TreeItem
|
||||
nodeId={`error_${ind}`}
|
||||
label={<ListItemText primary={error} />}
|
||||
key={`error_${ind}`}
|
||||
onClick={() => goToLogLine('error', ind)}
|
||||
/>
|
||||
))}
|
||||
</TreeItem>
|
||||
)}
|
||||
{log?.warnings.length && (
|
||||
<TreeItem
|
||||
nodeId="warnings"
|
||||
label={
|
||||
<Typography>{`Warnings (${log.warnings.length})`}</Typography>
|
||||
}
|
||||
>
|
||||
{log.warnings &&
|
||||
log.warnings.map((warning, ind) => (
|
||||
<TreeItem
|
||||
nodeId={`warning_${ind}`}
|
||||
label={<ListItemText primary={warning} />}
|
||||
key={`warning_${ind}`}
|
||||
onClick={() => goToLogLine('warning', ind)}
|
||||
/>
|
||||
))}
|
||||
</TreeItem>
|
||||
)}
|
||||
</TreeView>
|
||||
</div>
|
||||
</div>
|
||||
{log?.errors.length !== 0 && (
|
||||
<TreeItem
|
||||
nodeId="errors"
|
||||
label={
|
||||
<Typography color="error">
|
||||
{`Errors (${log.errors.length})`}
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
{log.errors &&
|
||||
log.errors.map((error, ind) => (
|
||||
<TreeItem
|
||||
nodeId={`error_${ind}`}
|
||||
label={<ListItemText primary={error} />}
|
||||
key={`error_${ind}`}
|
||||
onClick={() => goToLogLine('error', ind)}
|
||||
/>
|
||||
))}
|
||||
</TreeItem>
|
||||
)}
|
||||
{log?.warnings.length !== 0 && (
|
||||
<TreeItem
|
||||
nodeId="warnings"
|
||||
label={
|
||||
<Typography>{`Warnings (${log.warnings.length})`}</Typography>
|
||||
}
|
||||
>
|
||||
{log.warnings &&
|
||||
log.warnings.map((warning, ind) => (
|
||||
<TreeItem
|
||||
nodeId={`warning_${ind}`}
|
||||
label={<ListItemText primary={warning} />}
|
||||
key={`warning_${ind}`}
|
||||
onClick={() => goToLogLine('warning', ind)}
|
||||
/>
|
||||
))}
|
||||
</TreeItem>
|
||||
)}
|
||||
</TreeView>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Typography
|
||||
id={`log_container`}
|
||||
variant="h5"
|
||||
className={classes.expansionDescription}
|
||||
>
|
||||
<Highlight className={'html'} innerHTML={true}>
|
||||
{decodeHtml(log?.body || '')}
|
||||
</Highlight>
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography
|
||||
id={`log_container`}
|
||||
variant="h5"
|
||||
className={classes.expansionDescription}
|
||||
>
|
||||
<Highlight className={'html'} innerHTML={true}>
|
||||
{decodeHtml(log?.body || '')}
|
||||
</Highlight>
|
||||
</Typography>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<h2>Log</h2>
|
||||
<pre
|
||||
id="log"
|
||||
style={{ overflow: 'auto', height: 'calc(100vh - 220px)' }}
|
||||
>
|
||||
{log}
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,14 @@ const LogTabWithIcons = (props: LogTabProps) => {
|
||||
gap: 6,
|
||||
alignItems: 'center'
|
||||
}}
|
||||
onClick={() => {
|
||||
const logWrapper = document.querySelector(`#logWrapper`)
|
||||
|
||||
if (logWrapper) logWrapper.scrollTop = 0
|
||||
}}
|
||||
>
|
||||
<span>log</span>
|
||||
{errors.length && <ErrorOutline color="error" style={{ fontSize: 20 }} />}
|
||||
{warnings.length && <Warning style={{ fontSize: 20 }} />}{' '}
|
||||
{errors.length !== 0 && (
|
||||
<ErrorOutline color="error" style={{ fontSize: 20 }} />
|
||||
)}
|
||||
{warnings.length !== 0 && (
|
||||
<Warning style={{ fontSize: 20, color: 'green' }} />
|
||||
)}{' '}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
useSnackbar,
|
||||
useStateWithCallback
|
||||
} from '../../../../utils/hooks'
|
||||
import { parseErrorsAndWarnings, LogObject } from '../../../../utils'
|
||||
|
||||
const SASJS_LOGS_SEPARATOR =
|
||||
'SASJS_LOGS_SEPARATOR_163ee17b6ff24f028928972d80a26784'
|
||||
@@ -41,10 +42,12 @@ const useEditor = ({
|
||||
|
||||
const [prevFileContent, setPrevFileContent] = useStateWithCallback('')
|
||||
const [fileContent, setFileContent] = useState('')
|
||||
const [log, setLog] = useState('')
|
||||
const [log, setLog] = useState<LogObject>()
|
||||
const [webout, setWebout] = useState('')
|
||||
const [runTimes, setRunTimes] = useState<string[]>([])
|
||||
const [selectedRunTime, setSelectedRunTime] = useState('')
|
||||
const [selectedRunTime, setSelectedRunTime] = useState<RunTimeType>(
|
||||
RunTimeType.SAS
|
||||
)
|
||||
const [selectedFileExtension, setSelectedFileExtension] = useState('')
|
||||
const [openFilePathInputModal, setOpenFilePathInputModal] = useState(false)
|
||||
const [showDiff, setShowDiff] = useState(false)
|
||||
@@ -150,6 +153,13 @@ const useEditor = ({
|
||||
const runCode = useCallback(
|
||||
(code: string) => {
|
||||
setIsLoading(true)
|
||||
|
||||
// Scroll to bottom of log
|
||||
const logElement = document.getElementById('log')
|
||||
if (logElement) logElement.scrollTop = logElement.scrollHeight
|
||||
|
||||
setIsLoading(false)
|
||||
|
||||
axios
|
||||
.post(`/SASjsApi/code/execute`, {
|
||||
code: programPathInjection(
|
||||
@@ -160,8 +170,18 @@ const useEditor = ({
|
||||
runTime: selectedRunTime
|
||||
})
|
||||
.then((res: any) => {
|
||||
const { errors, warnings, logLines } = parseErrorsAndWarnings(
|
||||
res.data.split(SASJS_LOGS_SEPARATOR)[1]
|
||||
)
|
||||
|
||||
const log: LogObject = {
|
||||
body: logLines.join(`\n`),
|
||||
errors,
|
||||
warnings
|
||||
}
|
||||
|
||||
setWebout(res.data.split(SASJS_LOGS_SEPARATOR)[0] ?? '')
|
||||
setLog(res.data.split(SASJS_LOGS_SEPARATOR)[1] ?? '')
|
||||
setLog(log)
|
||||
setTab('log')
|
||||
|
||||
// Scroll to bottom of log
|
||||
@@ -249,7 +269,7 @@ const useEditor = ({
|
||||
}, [appContext.runTimes])
|
||||
|
||||
useEffect(() => {
|
||||
if (runTimes.length) setSelectedRunTime(runTimes[0])
|
||||
if (runTimes.length) setSelectedRunTime(runTimes[0] as RunTimeType)
|
||||
}, [runTimes])
|
||||
|
||||
useEffect(() => {
|
||||
@@ -280,7 +300,6 @@ const useEditor = ({
|
||||
const content = localStorage.getItem('fileContent') ?? ''
|
||||
setFileContent(content)
|
||||
}
|
||||
setLog('')
|
||||
setWebout('')
|
||||
setTab('code')
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -294,7 +313,9 @@ const useEditor = ({
|
||||
|
||||
useEffect(() => {
|
||||
const fileExtension = selectedFileExtension.toLowerCase()
|
||||
if (runTimes.includes(fileExtension)) setSelectedRunTime(fileExtension)
|
||||
|
||||
if (runTimes.includes(fileExtension))
|
||||
setSelectedRunTime(fileExtension as RunTimeType)
|
||||
}, [selectedFileExtension, runTimes])
|
||||
|
||||
return {
|
||||
|
||||
@@ -15,7 +15,7 @@ export const parseErrorsAndWarnings = (log: string) => {
|
||||
errorLines.push(line)
|
||||
|
||||
logLines[index] =
|
||||
`<font id="error_${errorLines.length - 1}">` +
|
||||
`<font id="error_${errorLines.length - 1}" style="color: red;">` +
|
||||
logLines[index] +
|
||||
'</font>'
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export const parseErrorsAndWarnings = (log: string) => {
|
||||
warningLines.push(line)
|
||||
|
||||
logLines[index] =
|
||||
`<font id="warning_${warningLines.length - 1}">` +
|
||||
`<font id="warning_${warningLines.length - 1}" style="color: green;">` +
|
||||
logLines[index] +
|
||||
'</font>'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user