1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-11 03:34:35 +00:00

Compare commits

...

33 Commits

Author SHA1 Message Date
semantic-release-bot
4f1763db67 chore(release): 0.35.3 [skip ci]
## [0.35.3](https://github.com/sasjs/server/compare/v0.35.2...v0.35.3) (2023-11-07)

### Bug Fixes

* enable embedded LFs in JS STP vars ([7e8cbbf](7e8cbbf377))
2023-11-07 20:48:28 +00:00
Allan Bowe
28222add04 Merge pull request #370 from sasjs/allanbowe-patch-1
fix: enable embedded LFs in JS STP vars
2023-11-07 20:43:16 +00:00
Allan
068edfd6a5 chore: lint fix 2023-11-07 20:39:05 +00:00
Allan Bowe
7e8cbbf377 fix: enable embedded LFs in JS STP vars 2023-11-07 15:51:32 +00:00
Allan Bowe
1fc1431442 chore: using GITHUB_TOKEN 2023-08-07 20:11:40 +01:00
semantic-release-bot
3387efbb9a chore(release): 0.35.2 [skip ci]
## [0.35.2](https://github.com/sasjs/server/compare/v0.35.1...v0.35.2) (2023-08-07)

### Bug Fixes

* add _debug as optional query param in swagger apis for GET stp/execute ([9586dbb](9586dbb2d0))
2023-08-07 18:53:12 +00:00
Allan Bowe
e2996b495f Merge pull request #365 from sasjs/swagger-fix
fix: add _debug as optional query param in swagger apis for  stp/execute
2023-08-07 19:48:28 +01:00
Allan
41c627f93a chore: lint fix 2023-08-07 19:39:02 +01:00
Allan Bowe
49f5dc7555 Update swagger.yaml 2023-08-07 19:32:29 +01:00
Allan Bowe
f6e77f99a4 Update swagger.yaml 2023-08-07 19:31:20 +01:00
Allan Bowe
b57dfa429b Update stp.ts 2023-08-07 19:30:09 +01:00
9586dbb2d0 fix: add _debug as optional query param in swagger apis for GET stp/execute 2023-08-07 22:01:52 +05:00
semantic-release-bot
a4f78ab48d chore(release): 0.35.1 [skip ci]
## [0.35.1](https://github.com/sasjs/server/compare/v0.35.0...v0.35.1) (2023-07-25)

### Bug Fixes

* **log-separator:** log separator should always wrap log ([8940f4d](8940f4dc47))
2023-07-25 06:05:23 +00:00
Yury Shkoda
2f47a2213b Merge pull request #364 from sasjs/log-separator
fix(log-separator): log separator should always wrap log
2023-07-25 09:01:36 +03:00
Yury Shkoda
0f91395fbb lint: fixed linting issues 2023-07-24 18:36:08 +03:00
Yury Shkoda
167b14fed0 docs(log-separator): left comment 2023-07-24 18:29:20 +03:00
Yury Shkoda
8940f4dc47 fix(log-separator): log separator should always wrap log 2023-07-24 18:27:21 +03:00
semantic-release-bot
48c1ada1b6 chore(release): 0.35.0 [skip ci]
# [0.35.0](https://github.com/sasjs/server/compare/v0.34.2...v0.35.0) (2023-05-03)

### Bug Fixes

* **editor:** fixed log/webout/print tabs ([d2de9dc](d2de9dc13e))
* **execute:** added atribute indicating stp api ([e78f87f](e78f87f5c0))
* **execute:** fixed adding print output ([9aaffce](9aaffce820))
* **execution:** removed empty webout from response ([6dd2f4f](6dd2f4f876))
* **webout:** fixed adding empty webout to response payload ([31df72a](31df72ad88))

### Features

* **editor:** parse print output in response payload ([eb42683](eb42683fff))
2023-05-03 09:34:56 +00:00
Allan Bowe
0532488b55 Merge pull request #360 from sasjs/issue-354
Support print destination natively
2023-05-03 10:31:06 +01:00
Yury Shkoda
d458b5bb81 chore: cleanup 2023-05-03 10:56:17 +03:00
Yury Shkoda
958ab9cad2 chore(execution): add includePrintOutput to ExecuteFileParams 2023-05-03 10:46:21 +03:00
Yury Shkoda
78ceed13e1 docs(code): updated execute endpoint info 2023-05-02 16:01:00 +03:00
Yury Shkoda
a17814fc90 chore(stp): removed redundant argument 2023-05-02 15:53:13 +03:00
Yury Shkoda
9aaffce820 fix(execute): fixed adding print output 2023-05-02 15:49:44 +03:00
Yury Shkoda
e78f87f5c0 fix(execute): added atribute indicating stp api 2023-05-02 15:18:05 +03:00
Yury Shkoda
bd1b58086d docs: left a comment regarding payload parts 2023-05-02 12:10:17 +03:00
Yury Shkoda
9f521634d9 chore(webout): added comment 2023-05-02 11:30:55 +03:00
Yury Shkoda
a696168443 Merge branch 'main' of github.com:sasjs/server into issue-354 2023-05-02 11:17:41 +03:00
Yury Shkoda
31df72ad88 fix(webout): fixed adding empty webout to response payload 2023-05-02 11:17:12 +03:00
Yury Shkoda
eb42683fff feat(editor): parse print output in response payload 2023-05-01 08:18:49 +03:00
Yury Shkoda
d2de9dc13e fix(editor): fixed log/webout/print tabs 2023-05-01 07:28:23 +03:00
Yury Shkoda
6dd2f4f876 fix(execution): removed empty webout from response 2023-04-28 17:25:30 +03:00
Yury Shkoda
c0f38ba7c9 wip(print-output): added print output to response payload 2023-04-28 15:09:44 +03:00
17 changed files with 193 additions and 82 deletions

View File

@@ -56,4 +56,4 @@ jobs:
- name: Release - name: Release
run: | run: |
GITHUB_TOKEN=${{ secrets.GH_TOKEN }} semantic-release GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} semantic-release

View File

@@ -1,3 +1,40 @@
## [0.35.3](https://github.com/sasjs/server/compare/v0.35.2...v0.35.3) (2023-11-07)
### Bug Fixes
* enable embedded LFs in JS STP vars ([7e8cbbf](https://github.com/sasjs/server/commit/7e8cbbf377b27a7f5dd9af0bc6605c01f302f5d9))
## [0.35.2](https://github.com/sasjs/server/compare/v0.35.1...v0.35.2) (2023-08-07)
### Bug Fixes
* add _debug as optional query param in swagger apis for GET stp/execute ([9586dbb](https://github.com/sasjs/server/commit/9586dbb2d0d6611061c9efdfb84030144f62c2ee))
## [0.35.1](https://github.com/sasjs/server/compare/v0.35.0...v0.35.1) (2023-07-25)
### Bug Fixes
* **log-separator:** log separator should always wrap log ([8940f4d](https://github.com/sasjs/server/commit/8940f4dc47abae2036b4fcdeb772c31a0ca07cca))
# [0.35.0](https://github.com/sasjs/server/compare/v0.34.2...v0.35.0) (2023-05-03)
### Bug Fixes
* **editor:** fixed log/webout/print tabs ([d2de9dc](https://github.com/sasjs/server/commit/d2de9dc13ef2e980286dd03cca5e22cea443ed0c))
* **execute:** added atribute indicating stp api ([e78f87f](https://github.com/sasjs/server/commit/e78f87f5c00038ea11261dffb525ac8f1024e40b))
* **execute:** fixed adding print output ([9aaffce](https://github.com/sasjs/server/commit/9aaffce82051d81bf39adb69942bb321e9795141))
* **execution:** removed empty webout from response ([6dd2f4f](https://github.com/sasjs/server/commit/6dd2f4f87673336135bc7a6de0d2e143e192c025))
* **webout:** fixed adding empty webout to response payload ([31df72a](https://github.com/sasjs/server/commit/31df72ad88fe2c771d0ef8445d6db9dd147c40c9))
### Features
* **editor:** parse print output in response payload ([eb42683](https://github.com/sasjs/server/commit/eb42683fff701bd5b4d2b68760fe0c3ecad573dd))
## [0.34.2](https://github.com/sasjs/server/compare/v0.34.1...v0.34.2) (2023-05-01) ## [0.34.2](https://github.com/sasjs/server/compare/v0.34.1...v0.34.2) (2023-05-01)

View File

@@ -158,7 +158,7 @@ CORS=
WHITELIST= WHITELIST=
# HELMET Cross Origin Embedder Policy # HELMET Cross Origin Embedder Policy
# Sets the Cross-Origin-Embedder-Policy header to require-corp when `true` # Sets the Cross-Origin-Embedder-Policy header to require-corp when `true`
# options: [true|false] default: true # options: [true|false] default: true
# Docs: https://helmetjs.github.io/#reference (`crossOriginEmbedderPolicy`) # Docs: https://helmetjs.github.io/#reference (`crossOriginEmbedderPolicy`)
HELMET_COEP= HELMET_COEP=

View File

@@ -792,7 +792,7 @@ paths:
- {type: string} - {type: string}
- {type: string, format: byte} - {type: string, format: byte}
description: 'Execute Code on the Specified Runtime' description: 'Execute Code on the Specified Runtime'
summary: 'Run Code and Return Webout Content and Log' summary: "Run Code and Return Webout Content, Log and Print output\nThe order of returned parts of the payload is:\n1. Webout (if present)\n2. Logs UUID (used as separator)\n3. Log\n4. Logs UUID (used as separator)\n5. Print (if present and if the runtime is SAS)\nPlease see"
tags: tags:
- Code - Code
security: security:
@@ -1798,13 +1798,22 @@ paths:
bearerAuth: [] bearerAuth: []
parameters: parameters:
- -
description: 'Location of code in SASjs Drive' description: 'Location of the Stored Program in SASjs Drive'
in: query in: query
name: _program name: _program
required: true required: true
schema: schema:
type: string type: string
example: /Projects/myApp/some/program example: /Projects/myApp/some/program
-
description: 'Optional query param for setting debug mode (returns the session log in the response body)'
in: query
name: _debug
required: false
schema:
format: double
type: number
example: 131
post: post:
operationId: ExecutePostRequest operationId: ExecutePostRequest
responses: responses:

View File

@@ -28,7 +28,14 @@ interface ExecuteCodePayload {
export class CodeController { export class CodeController {
/** /**
* Execute Code on the Specified Runtime * Execute Code on the Specified Runtime
* @summary Run Code and Return Webout Content and Log * @summary Run Code and Return Webout Content, Log and Print output
* The order of returned parts of the payload is:
* 1. Webout (if present)
* 2. Logs UUID (used as separator)
* 3. Log
* 4. Logs UUID (used as separator)
* 5. Print (if present and if the runtime is SAS)
* Please see @sasjs/server/api/src/controllers/internal/Execution.ts for more information
*/ */
@Post('/execute') @Post('/execute')
public async executeCode( public async executeCode(
@@ -55,7 +62,8 @@ const executeCode = async (
preProgramVariables: getPreProgramVariables(req), preProgramVariables: getPreProgramVariables(req),
vars: { ...req.query, _debug: 131 }, vars: { ...req.query, _debug: 131 },
otherArgs: { userAutoExec }, otherArgs: { userAutoExec },
runTime: runTime runTime: runTime,
includePrintOutput: true
}) })
return result return result

View File

@@ -33,6 +33,7 @@ interface ExecuteFileParams {
interface ExecuteProgramParams extends Omit<ExecuteFileParams, 'programPath'> { interface ExecuteProgramParams extends Omit<ExecuteFileParams, 'programPath'> {
program: string program: string
includePrintOutput?: boolean
} }
export class ExecutionController { export class ExecutionController {
@@ -67,7 +68,8 @@ export class ExecutionController {
otherArgs, otherArgs,
session: sessionByFileUpload, session: sessionByFileUpload,
runTime, runTime,
forceStringResult forceStringResult,
includePrintOutput
}: ExecuteProgramParams): Promise<ExecuteReturnRaw> { }: ExecuteProgramParams): Promise<ExecuteReturnRaw> {
const sessionController = getSessionController(runTime) const sessionController = getSessionController(runTime)
@@ -78,7 +80,6 @@ export class ExecutionController {
const logPath = path.join(session.path, 'log.log') const logPath = path.join(session.path, 'log.log')
const headersPath = path.join(session.path, 'stpsrv_header.txt') const headersPath = path.join(session.path, 'stpsrv_header.txt')
const weboutPath = path.join(session.path, 'webout.txt') const weboutPath = path.join(session.path, 'webout.txt')
const tokenFile = path.join(session.path, 'reqHeaders.txt') const tokenFile = path.join(session.path, 'reqHeaders.txt')
@@ -122,12 +123,29 @@ export class ExecutionController {
// it should be deleted by scheduleSessionDestroy // it should be deleted by scheduleSessionDestroy
session.inUse = false session.inUse = false
const resultParts = []
// INFO: webout can be a Buffer, that is why it's length should be checked to determine if it is empty
if (webout && webout.length !== 0) resultParts.push(webout)
// INFO: log separator wraps the log from the beginning and the end
resultParts.push(process.logsUUID)
resultParts.push(log)
resultParts.push(process.logsUUID)
if (includePrintOutput && runTime === RunTimeType.SAS) {
const printOutputPath = path.join(session.path, 'output.lst')
const printOutput = (await fileExists(printOutputPath))
? await readFile(printOutputPath)
: ''
if (printOutput) resultParts.push(printOutput)
}
return { return {
httpHeaders, httpHeaders,
result: result:
isDebugOn(vars) || session.crashed isDebugOn(vars) || session.crashed ? resultParts.join(`\n`) : webout
? `${webout}\n${process.logsUUID}\n${log}`
: webout
} }
} }

View File

@@ -190,7 +190,8 @@ ${autoExecContent}`
} }
private scheduleSessionDestroy(session: Session) { private scheduleSessionDestroy(session: Session) {
setTimeout(async () => { setTimeout(
async () => {
if (session.inUse) { if (session.inUse) {
// adding 10 more minutes // adding 10 more minutes
const newDeathTimeStamp = parseInt(session.deathTimeStamp) + 10 * 1000 const newDeathTimeStamp = parseInt(session.deathTimeStamp) + 10 * 1000
@@ -200,7 +201,9 @@ ${autoExecContent}`
} else { } else {
await this.deleteSession(session) await this.deleteSession(session)
} }
}, parseInt(session.deathTimeStamp) - new Date().getTime() - 100) },
parseInt(session.deathTimeStamp) - new Date().getTime() - 100
)
} }
} }

View File

@@ -15,7 +15,7 @@ export const createJSProgram = async (
) => { ) => {
const varStatments = Object.keys(vars).reduce( const varStatments = Object.keys(vars).reduce(
(computed: string, key: string) => (computed: string, key: string) =>
`${computed}const ${key} = '${vars[key]}';\n`, `${computed}const ${key} = \`${vars[key]}\`;\n`,
'' ''
) )

View File

@@ -3,12 +3,11 @@ import { Request, Security, Route, Tags, Post, Body, Get, Query } from 'tsoa'
import { ExecutionController, ExecutionVars } from './internal' import { ExecutionController, ExecutionVars } from './internal'
import { import {
getPreProgramVariables, getPreProgramVariables,
HTTPHeaders,
LogLine,
makeFilesNamesMap, makeFilesNamesMap,
getRunTimeAndFilePath getRunTimeAndFilePath
} from '../utils' } from '../utils'
import { MulterFile } from '../types/Upload' import { MulterFile } from '../types/Upload'
import { debug } from 'console'
interface ExecutePostRequestPayload { interface ExecutePostRequestPayload {
/** /**
@@ -25,20 +24,31 @@ export class STPController {
/** /**
* Trigger a Stored Program using the _program URL parameter. * Trigger a Stored Program using the _program URL parameter.
* *
* Accepts URL parameters and file uploads. For more details, see docs: * Accepts additional URL parameters (converted to session variables)
* and file uploads. For more details, see docs:
* *
* https://server.sasjs.io/storedprograms * https://server.sasjs.io/storedprograms
* *
* @summary Execute a Stored Program, returns _webout and (optionally) log. * @summary Execute a Stored Program, returns _webout and (optionally) log.
* @param _program Location of code in SASjs Drive * @param _program Location of code in SASjs Drive
* @param _debug Optional query param for setting debug mode, which will return the session log.
* @example _program "/Projects/myApp/some/program" * @example _program "/Projects/myApp/some/program"
* @example _debug 131
*/ */
@Get('/execute') @Get('/execute')
public async executeGetRequest( public async executeGetRequest(
@Request() request: express.Request, @Request() request: express.Request,
@Query() _program: string @Query() _program: string,
@Query() _debug?: number
): Promise<string | Buffer> { ): Promise<string | Buffer> {
const vars = request.query as ExecutionVars let vars = request.query as ExecutionVars
if (_debug) {
vars = {
...vars,
_debug
}
}
return execute(request, _program, vars) return execute(request, _program, vars)
} }

View File

@@ -13,7 +13,11 @@ stpRouter.get('/execute', async (req, res) => {
if (error) return res.status(400).send(error.details[0].message) if (error) return res.status(400).send(error.details[0].message)
try { try {
const response = await controller.executeGetRequest(req, query._program) const response = await controller.executeGetRequest(
req,
query._program,
query._debug
)
if (response instanceof Buffer) { if (response instanceof Buffer) {
res.writeHead(200, (req as any).sasHeaders) res.writeHead(200, (req as any).sasHeaders)

View File

@@ -51,9 +51,8 @@ export const generateFileUploadSasCode = async (
let fileCount = 0 let fileCount = 0
const uploadedFiles: UploadedFiles[] = [] const uploadedFiles: UploadedFiles[] = []
const sasSessionFolderList: string[] = await listFilesInFolder( const sasSessionFolderList: string[] =
sasSessionFolder await listFilesInFolder(sasSessionFolder)
)
sasSessionFolderList.forEach((fileName) => { sasSessionFolderList.forEach((fileName) => {
let fileCountString = fileCount < 100 ? '0' + fileCount : fileCount let fileCountString = fileCount < 100 ? '0' + fileCount : fileCount
fileCountString = fileCount < 10 ? '00' + fileCount : fileCount fileCountString = fileCount < 10 ? '00' + fileCount : fileCount

View File

@@ -180,7 +180,8 @@ export const runCodeValidation = (data: any): Joi.ValidationResult =>
export const executeProgramRawValidation = (data: any): Joi.ValidationResult => export const executeProgramRawValidation = (data: any): Joi.ValidationResult =>
Joi.object({ Joi.object({
_program: Joi.string().required() _program: Joi.string().required(),
_debug: Joi.number()
}) })
.pattern(/^/, Joi.alternatives(Joi.string(), Joi.number())) .pattern(/^/, Joi.alternatives(Joi.string(), Joi.number()))
.validate(data) .validate(data)

View File

@@ -3,12 +3,11 @@ import Snackbar from '@mui/material/Snackbar'
import MuiAlert, { AlertProps } from '@mui/material/Alert' import MuiAlert, { AlertProps } from '@mui/material/Alert'
import Slide, { SlideProps } from '@mui/material/Slide' import Slide, { SlideProps } from '@mui/material/Slide'
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(function Alert( const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
props, function Alert(props, ref) {
ref
) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} /> return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />
}) }
)
const Transition = (props: SlideProps) => { const Transition = (props: SlideProps) => {
return <Slide {...props} direction="up" /> return <Slide {...props} direction="up" />

View File

@@ -62,6 +62,7 @@ const SASjsEditor = ({
selectedRunTime, selectedRunTime,
showDiff, showDiff,
webout, webout,
printOutput,
Dialog, Dialog,
handleChangeRunTime, handleChangeRunTime,
handleDiffEditorDidMount, handleDiffEditorDidMount,
@@ -153,6 +154,7 @@ const SASjsEditor = ({
> >
<TabList onChange={handleTabChange} centered> <TabList onChange={handleTabChange} centered>
<StyledTab label="Code" value="code" /> <StyledTab label="Code" value="code" />
{log && (
<StyledTab <StyledTab
label={logWithErrorsOrWarnings ? '' : 'log'} label={logWithErrorsOrWarnings ? '' : 'log'}
value="log" value="log"
@@ -169,6 +171,8 @@ const SASjsEditor = ({
if (logWrapper) logWrapper.scrollTop = 0 if (logWrapper) logWrapper.scrollTop = 0
}} }}
/> />
)}
{webout && (
<StyledTab <StyledTab
label={ label={
<Tooltip title="Displays content from the _webout fileref"> <Tooltip title="Displays content from the _webout fileref">
@@ -177,6 +181,8 @@ const SASjsEditor = ({
} }
value="webout" value="webout"
/> />
)}
{printOutput && <StyledTab label="print" value="printOutput" />}
</TabList> </TabList>
</Box> </Box>
@@ -222,11 +228,20 @@ const SASjsEditor = ({
<LogComponent log={log} selectedRunTime={selectedRunTime} /> <LogComponent log={log} selectedRunTime={selectedRunTime} />
)} )}
</StyledTabPanel> </StyledTabPanel>
{webout && (
<StyledTabPanel value="webout"> <StyledTabPanel value="webout">
<div> <div>
<pre>{webout}</pre> <pre>{webout}</pre>
</div> </div>
</StyledTabPanel> </StyledTabPanel>
)}
{printOutput && (
<StyledTabPanel value="printOutput">
<div>
<pre>{printOutput}</pre>
</div>
</StyledTabPanel>
)}
</TabContext> </TabContext>
)} )}
<Dialog /> <Dialog />

View File

@@ -7,8 +7,10 @@
border: none; border: none;
outline: none; outline: none;
transition: 0.4s; transition: 0.4s;
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, box-shadow:
rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px; rgba(0, 0, 0, 0.2) 0px 2px 1px -1px,
rgba(0, 0, 0, 0.14) 0px 1px 1px 0px,
rgba(0, 0, 0, 0.12) 0px 1px 3px 0px;
} }
.ChunkDetails { .ChunkDetails {

View File

@@ -39,14 +39,14 @@ const useEditor = ({
const { Snackbar, setOpenSnackbar, setSnackbarMessage, setSnackbarSeverity } = const { Snackbar, setOpenSnackbar, setSnackbarMessage, setSnackbarSeverity } =
useSnackbar() useSnackbar()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [prevFileContent, setPrevFileContent] = useStateWithCallback('') const [prevFileContent, setPrevFileContent] = useStateWithCallback('')
const [fileContent, setFileContent] = useState('') const [fileContent, setFileContent] = useState('')
const [log, setLog] = useState<LogObject | string>() const [log, setLog] = useState<LogObject | string>()
const [webout, setWebout] = useState('') const [webout, setWebout] = useState<string>()
const [printOutput, setPrintOutput] = useState<string>()
const [runTimes, setRunTimes] = useState<string[]>([]) const [runTimes, setRunTimes] = useState<string[]>([])
const [selectedRunTime, setSelectedRunTime] = useState<RunTimeType | string>( const [selectedRunTime, setSelectedRunTime] = useState<RunTimeType>(
'' RunTimeType.SAS
) )
const [selectedFileExtension, setSelectedFileExtension] = useState('') const [selectedFileExtension, setSelectedFileExtension] = useState('')
const [openFilePathInputModal, setOpenFilePathInputModal] = useState(false) const [openFilePathInputModal, setOpenFilePathInputModal] = useState(false)
@@ -169,25 +169,30 @@ const useEditor = ({
), ),
runTime: selectedRunTime runTime: selectedRunTime
}) })
.then((res: any) => { .then((res: { data: string }) => {
if (selectedRunTime === RunTimeType.SAS) { // INFO: the order of payload parts is set in @sasjs/server/api/src/controllers/internal/Execution.ts
const { errors, warnings, logLines } = parseErrorsAndWarnings( const resDataSplitted = res.data.split(SASJS_LOGS_SEPARATOR)
res.data.split(SASJS_LOGS_SEPARATOR)[1] const webout = resDataSplitted[0]
) const log = resDataSplitted[1]
const printOutput = resDataSplitted[2]
const log: LogObject = { if (selectedRunTime === RunTimeType.SAS) {
const { errors, warnings, logLines } = parseErrorsAndWarnings(log)
const logObject: LogObject = {
body: logLines.join(`\n`), body: logLines.join(`\n`),
errors, errors,
warnings, warnings,
linesCount: logLines.length linesCount: logLines.length
} }
setLog(log) setLog(logObject)
} else { } else {
setLog(res.data.split(SASJS_LOGS_SEPARATOR)[1] ?? '') setLog(log)
} }
setWebout(res.data.split(SASJS_LOGS_SEPARATOR)[0] ?? '') setWebout(webout)
setPrintOutput(printOutput)
setTab('log') setTab('log')
// Scroll to bottom of log // Scroll to bottom of log
@@ -335,6 +340,7 @@ const useEditor = ({
selectedRunTime, selectedRunTime,
showDiff, showDiff,
webout, webout,
printOutput,
Dialog, Dialog,
handleChangeRunTime, handleChangeRunTime,
handleDiffEditorDidMount, handleDiffEditorDidMount,

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />