mirror of
https://github.com/sasjs/server.git
synced 2025-12-11 19:44:35 +00:00
fix: code/execute controller logic to handle different runtimes
This commit is contained in:
@@ -139,14 +139,24 @@ components:
|
|||||||
- httpHeaders
|
- httpHeaders
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
RunTimeType:
|
||||||
|
enum:
|
||||||
|
- sas
|
||||||
|
- js
|
||||||
|
type: string
|
||||||
ExecuteSASCodePayload:
|
ExecuteSASCodePayload:
|
||||||
properties:
|
properties:
|
||||||
code:
|
code:
|
||||||
type: string
|
type: string
|
||||||
description: 'Code of SAS program'
|
description: 'Code of program'
|
||||||
example: '* SAS Code HERE;'
|
example: '* Code HERE;'
|
||||||
|
runTime:
|
||||||
|
$ref: '#/components/schemas/RunTimeType'
|
||||||
|
description: 'runtime for program'
|
||||||
|
example: js
|
||||||
required:
|
required:
|
||||||
- code
|
- code
|
||||||
|
- runTime
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
MemberType.folder:
|
MemberType.folder:
|
||||||
@@ -437,11 +447,16 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
protocol:
|
protocol:
|
||||||
type: string
|
type: string
|
||||||
|
runTimes:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
required:
|
required:
|
||||||
- mode
|
- mode
|
||||||
- cors
|
- cors
|
||||||
- whiteList
|
- whiteList
|
||||||
- protocol
|
- protocol
|
||||||
|
- runTimes
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
ExecuteReturnJsonPayload:
|
ExecuteReturnJsonPayload:
|
||||||
@@ -1349,7 +1364,7 @@ paths:
|
|||||||
$ref: '#/components/schemas/InfoResponse'
|
$ref: '#/components/schemas/InfoResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {mode: desktop, cors: enable, whiteList: ['http://example.com', 'http://example2.com'], protocol: http}
|
value: {mode: desktop, cors: enable, whiteList: ['http://example.com', 'http://example2.com'], protocol: http, runTimes: [sas, js]}
|
||||||
summary: 'Get server info (mode, cors, whiteList, protocol).'
|
summary: 'Get server info (mode, cors, whiteList, protocol).'
|
||||||
tags:
|
tags:
|
||||||
- Info
|
- Info
|
||||||
@@ -1387,8 +1402,8 @@ paths:
|
|||||||
anyOf:
|
anyOf:
|
||||||
- {type: string}
|
- {type: string}
|
||||||
- {type: string, format: byte}
|
- {type: string, format: byte}
|
||||||
description: "Trigger a SAS program using it's location in the _program URL parameter.\nEnable debugging using the _debug URL parameter. Setting _debug=131 will\ncause the log to be streamed in the output.\n\nAdditional URL parameters are turned into SAS macro variables.\n\nAny files provided in the request body are placed into the SAS session with\ncorresponding _WEBIN_XXX variables created.\n\nThe response headers can be adjusted using the mfs_httpheader() macro. Any\nfile type can be returned, including binary files such as zip or xls.\n\nIf _debug is >= 131, response headers will contain Content-Type: 'text/plain'\n\nThis behaviour differs for POST requests, in which case the response is\nalways JSON."
|
description: "Trigger a SAS or JS program using the _program URL parameter.\n\nAccepts URL parameters and file uploads. For more details, see docs:\n\nhttps://server.sasjs.io/storedprograms"
|
||||||
summary: 'Execute Stored Program, return raw _webout content.'
|
summary: 'Execute a Stored Program, returns raw _webout content.'
|
||||||
tags:
|
tags:
|
||||||
- STP
|
- STP
|
||||||
security:
|
security:
|
||||||
@@ -1396,13 +1411,13 @@ paths:
|
|||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
parameters:
|
parameters:
|
||||||
-
|
-
|
||||||
description: 'Location of SAS program'
|
description: 'Location of SAS or JS code'
|
||||||
in: query
|
in: query
|
||||||
name: _program
|
name: _program
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
example: /Public/somefolder/some.file
|
example: /Projects/myApp/some/program
|
||||||
post:
|
post:
|
||||||
operationId: ExecuteReturnJson
|
operationId: ExecuteReturnJson
|
||||||
responses:
|
responses:
|
||||||
@@ -1415,8 +1430,8 @@ paths:
|
|||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {status: success, _webout: 'webout content', log: [], httpHeaders: {Content-type: application/zip, Cache-Control: 'public, max-age=1000'}}
|
value: {status: success, _webout: 'webout content', log: [], httpHeaders: {Content-type: application/zip, Cache-Control: 'public, max-age=1000'}}
|
||||||
description: "Trigger a SAS program using it's location in the _program URL parameter.\nEnable debugging using the _debug URL parameter. In any case, the log is\nalways returned in the log object.\n\nAdditional URL parameters are turned into SAS macro variables.\n\nAny files provided in the request body are placed into the SAS session with\ncorresponding _WEBIN_XXX variables created.\n\nThe response will be a JSON object with the following root attributes: log,\nwebout, headers.\n\nThe webout will be a nested JSON object ONLY if the response-header\ncontains a content-type of application/json AND it is valid JSON.\nOtherwise it will be a stringified version of the webout content.\n\nResponse headers from the mfs_httpheader macro are simply listed in the\nheaders object, for POST requests they have no effect on the actual\nresponse header."
|
description: "Trigger a SAS or JS program using the _program URL parameter.\n\nAccepts URL parameters and file uploads. For more details, see docs:\n\nhttps://server.sasjs.io/storedprograms\n\nThe response will be a JSON object with the following root attributes:\nlog, webout, headers.\n\nThe webout attribute will be nested JSON ONLY if the response-header\ncontains a content-type of application/json AND it is valid JSON.\nOtherwise it will be a stringified version of the webout content."
|
||||||
summary: 'Execute Stored Program, return JSON'
|
summary: 'Execute a Stored Program, return a JSON object'
|
||||||
tags:
|
tags:
|
||||||
- STP
|
- STP
|
||||||
security:
|
security:
|
||||||
@@ -1424,13 +1439,13 @@ paths:
|
|||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
parameters:
|
parameters:
|
||||||
-
|
-
|
||||||
description: 'Location of SAS program'
|
description: 'Location of SAS or JS code'
|
||||||
in: query
|
in: query
|
||||||
name: _program
|
name: _program
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
example: /Public/somefolder/some.file
|
example: /Projects/myApp/some/program
|
||||||
requestBody:
|
requestBody:
|
||||||
required: false
|
required: false
|
||||||
content:
|
content:
|
||||||
|
|||||||
@@ -12,10 +12,15 @@ import {
|
|||||||
|
|
||||||
interface ExecuteSASCodePayload {
|
interface ExecuteSASCodePayload {
|
||||||
/**
|
/**
|
||||||
* Code of SAS program
|
* Code of program
|
||||||
* @example "* SAS Code HERE;"
|
* @example "* Code HERE;"
|
||||||
*/
|
*/
|
||||||
code: string
|
code: string
|
||||||
|
/**
|
||||||
|
* runtime for program
|
||||||
|
* @example "js"
|
||||||
|
*/
|
||||||
|
runTime: RunTimeType
|
||||||
}
|
}
|
||||||
|
|
||||||
@Security('bearerAuth')
|
@Security('bearerAuth')
|
||||||
@@ -37,7 +42,7 @@ export class CodeController {
|
|||||||
|
|
||||||
const executeSASCode = async (
|
const executeSASCode = async (
|
||||||
req: express.Request,
|
req: express.Request,
|
||||||
{ code }: ExecuteSASCodePayload
|
{ code, runTime }: ExecuteSASCodePayload
|
||||||
) => {
|
) => {
|
||||||
const { user } = req
|
const { user } = req
|
||||||
const userAutoExec =
|
const userAutoExec =
|
||||||
@@ -53,7 +58,7 @@ const executeSASCode = async (
|
|||||||
vars: { ...req.query, _debug: 131 },
|
vars: { ...req.query, _debug: 131 },
|
||||||
otherArgs: { userAutoExec },
|
otherArgs: { userAutoExec },
|
||||||
returnJson: true,
|
returnJson: true,
|
||||||
runTime: RunTimeType.SAS
|
runTime: runTime
|
||||||
})) as ExecuteReturnJson
|
})) as ExecuteReturnJson
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export interface InfoResponse {
|
|||||||
cors: string
|
cors: string
|
||||||
whiteList: string[]
|
whiteList: string[]
|
||||||
protocol: string
|
protocol: string
|
||||||
|
runTimes: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Route('SASjsApi/info')
|
@Route('SASjsApi/info')
|
||||||
@@ -18,7 +19,8 @@ export class InfoController {
|
|||||||
mode: 'desktop',
|
mode: 'desktop',
|
||||||
cors: 'enable',
|
cors: 'enable',
|
||||||
whiteList: ['http://example.com', 'http://example2.com'],
|
whiteList: ['http://example.com', 'http://example2.com'],
|
||||||
protocol: 'http'
|
protocol: 'http',
|
||||||
|
runTimes: ['sas', 'js']
|
||||||
})
|
})
|
||||||
@Get('/')
|
@Get('/')
|
||||||
public info(): InfoResponse {
|
public info(): InfoResponse {
|
||||||
@@ -29,7 +31,8 @@ export class InfoController {
|
|||||||
(process.env.MODE === 'server' ? 'disable' : 'enable'),
|
(process.env.MODE === 'server' ? 'disable' : 'enable'),
|
||||||
whiteList:
|
whiteList:
|
||||||
process.env.WHITELIST?.split(' ')?.filter((url) => !!url) ?? [],
|
process.env.WHITELIST?.split(' ')?.filter((url) => !!url) ?? [],
|
||||||
protocol: process.env.PROTOCOL ?? 'http'
|
protocol: process.env.PROTOCOL ?? 'http',
|
||||||
|
runTimes: process.runTimes
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ const createJSProgram = async (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const preProgramVarStatments = `
|
const preProgramVarStatments = `
|
||||||
|
let _webout = '';
|
||||||
const weboutPath = '${weboutPath}';
|
const weboutPath = '${weboutPath}';
|
||||||
const _sasjs_tokenfile = '${tokenFile}';
|
const _sasjs_tokenfile = '${tokenFile}';
|
||||||
const _sasjs_username = '${preProgramVariables?.username}';
|
const _sasjs_username = '${preProgramVariables?.username}';
|
||||||
@@ -296,10 +297,12 @@ ${preProgramVarStatments}
|
|||||||
/* actual job code */
|
/* actual job code */
|
||||||
${program}
|
${program}
|
||||||
|
|
||||||
/* write webout file*/
|
/* write webout file only if webout exists*/
|
||||||
|
if (_webout) {
|
||||||
fs.writeFile(weboutPath, _webout, function (err) {
|
fs.writeFile(weboutPath, _webout, function (err) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
})
|
})
|
||||||
|
}
|
||||||
`
|
`
|
||||||
// if no files are uploaded filesNamesMap will be undefined
|
// if no files are uploaded filesNamesMap will be undefined
|
||||||
if (otherArgs?.filesNamesMap) {
|
if (otherArgs?.filesNamesMap) {
|
||||||
|
|||||||
@@ -51,26 +51,15 @@ export interface ExecuteReturnJsonResponse {
|
|||||||
@Tags('STP')
|
@Tags('STP')
|
||||||
export class STPController {
|
export class STPController {
|
||||||
/**
|
/**
|
||||||
* Trigger a SAS program using it's location in the _program URL parameter.
|
* Trigger a SAS or JS program using the _program URL parameter.
|
||||||
* Enable debugging using the _debug URL parameter. Setting _debug=131 will
|
|
||||||
* cause the log to be streamed in the output.
|
|
||||||
*
|
*
|
||||||
* Additional URL parameters are turned into SAS macro variables.
|
* Accepts URL parameters and file uploads. For more details, see docs:
|
||||||
*
|
*
|
||||||
* Any files provided in the request body are placed into the SAS session with
|
* https://server.sasjs.io/storedprograms
|
||||||
* corresponding _WEBIN_XXX variables created.
|
|
||||||
*
|
*
|
||||||
* The response headers can be adjusted using the mfs_httpheader() macro. Any
|
* @summary Execute a Stored Program, returns raw _webout content.
|
||||||
* file type can be returned, including binary files such as zip or xls.
|
* @param _program Location of SAS or JS code
|
||||||
*
|
* @example _program "/Projects/myApp/some/program"
|
||||||
* If _debug is >= 131, response headers will contain Content-Type: 'text/plain'
|
|
||||||
*
|
|
||||||
* This behaviour differs for POST requests, in which case the response is
|
|
||||||
* always JSON.
|
|
||||||
*
|
|
||||||
* @summary Execute Stored Program, return raw _webout content.
|
|
||||||
* @param _program Location of SAS program
|
|
||||||
* @example _program "/Public/somefolder/some.file"
|
|
||||||
*/
|
*/
|
||||||
@Get('/execute')
|
@Get('/execute')
|
||||||
public async executeReturnRaw(
|
public async executeReturnRaw(
|
||||||
@@ -81,29 +70,22 @@ export class STPController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger a SAS program using it's location in the _program URL parameter.
|
* Trigger a SAS or JS program using the _program URL parameter.
|
||||||
* Enable debugging using the _debug URL parameter. In any case, the log is
|
|
||||||
* always returned in the log object.
|
|
||||||
*
|
*
|
||||||
* Additional URL parameters are turned into SAS macro variables.
|
* Accepts URL parameters and file uploads. For more details, see docs:
|
||||||
*
|
*
|
||||||
* Any files provided in the request body are placed into the SAS session with
|
* https://server.sasjs.io/storedprograms
|
||||||
* corresponding _WEBIN_XXX variables created.
|
|
||||||
*
|
*
|
||||||
* The response will be a JSON object with the following root attributes: log,
|
* The response will be a JSON object with the following root attributes:
|
||||||
* webout, headers.
|
* log, webout, headers.
|
||||||
*
|
*
|
||||||
* The webout will be a nested JSON object ONLY if the response-header
|
* The webout attribute will be nested JSON ONLY if the response-header
|
||||||
* contains a content-type of application/json AND it is valid JSON.
|
* contains a content-type of application/json AND it is valid JSON.
|
||||||
* Otherwise it will be a stringified version of the webout content.
|
* Otherwise it will be a stringified version of the webout content.
|
||||||
*
|
*
|
||||||
* Response headers from the mfs_httpheader macro are simply listed in the
|
* @summary Execute a Stored Program, return a JSON object
|
||||||
* headers object, for POST requests they have no effect on the actual
|
* @param _program Location of SAS or JS code
|
||||||
* response header.
|
* @example _program "/Projects/myApp/some/program"
|
||||||
*
|
|
||||||
* @summary Execute Stored Program, return JSON
|
|
||||||
* @param _program Location of SAS program
|
|
||||||
* @example _program "/Public/somefolder/some.file"
|
|
||||||
*/
|
*/
|
||||||
@Example<ExecuteReturnJsonResponse>({
|
@Example<ExecuteReturnJsonResponse>({
|
||||||
status: 'success',
|
status: 'success',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { runSASValidation } from '../../utils'
|
import { runCodeValidation } from '../../utils'
|
||||||
import { CodeController } from '../../controllers/'
|
import { CodeController } from '../../controllers/'
|
||||||
|
|
||||||
const runRouter = express.Router()
|
const runRouter = express.Router()
|
||||||
@@ -7,7 +7,7 @@ const runRouter = express.Router()
|
|||||||
const controller = new CodeController()
|
const controller = new CodeController()
|
||||||
|
|
||||||
runRouter.post('/execute', async (req, res) => {
|
runRouter.post('/execute', async (req, res) => {
|
||||||
const { error, value: body } = runSASValidation(req.body)
|
const { error, value: body } = runCodeValidation(req.body)
|
||||||
if (error) return res.status(400).send(error.details[0].message)
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Joi from 'joi'
|
import Joi from 'joi'
|
||||||
|
import { RunTimeType } from '.'
|
||||||
|
|
||||||
const usernameSchema = Joi.string().lowercase().alphanum().min(3).max(16)
|
const usernameSchema = Joi.string().lowercase().alphanum().min(3).max(16)
|
||||||
const passwordSchema = Joi.string().min(6).max(1024)
|
const passwordSchema = Joi.string().min(6).max(1024)
|
||||||
@@ -114,9 +115,10 @@ export const folderParamValidation = (data: any): Joi.ValidationResult =>
|
|||||||
_folderPath: Joi.string()
|
_folderPath: Joi.string()
|
||||||
}).validate(data)
|
}).validate(data)
|
||||||
|
|
||||||
export const runSASValidation = (data: any): Joi.ValidationResult =>
|
export const runCodeValidation = (data: any): Joi.ValidationResult =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
code: Joi.string().required()
|
code: Joi.string().required(),
|
||||||
|
runTime: Joi.string().valid(...Object.values(RunTimeType))
|
||||||
}).validate(data)
|
}).validate(data)
|
||||||
|
|
||||||
export const executeProgramRawValidation = (data: any): Joi.ValidationResult =>
|
export const executeProgramRawValidation = (data: any): Joi.ValidationResult =>
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState, useContext } from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import Box from '@mui/material/Box'
|
import {
|
||||||
import { Button, Paper, Stack, Tab, Tooltip } from '@mui/material'
|
Box,
|
||||||
|
MenuItem,
|
||||||
|
FormControl,
|
||||||
|
Select,
|
||||||
|
SelectChangeEvent,
|
||||||
|
Button,
|
||||||
|
Paper,
|
||||||
|
Tab,
|
||||||
|
Tooltip
|
||||||
|
} from '@mui/material'
|
||||||
import { makeStyles } from '@mui/styles'
|
import { makeStyles } from '@mui/styles'
|
||||||
import Editor, { EditorDidMount } from 'react-monaco-editor'
|
import Editor, { EditorDidMount } from 'react-monaco-editor'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import { TabContext, TabList, TabPanel } from '@mui/lab'
|
import { TabContext, TabList, TabPanel } from '@mui/lab'
|
||||||
|
|
||||||
|
import { AppContext, RunTimeType } from '../../context/appContext'
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
root: {
|
root: {
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
@@ -30,12 +41,14 @@ const useStyles = makeStyles(() => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const Studio = () => {
|
const Studio = () => {
|
||||||
|
const appContext = useContext(AppContext)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const [fileContent, setFileContent] = useState('')
|
const [fileContent, setFileContent] = useState('')
|
||||||
const [log, setLog] = useState('')
|
const [log, setLog] = useState('')
|
||||||
const [ctrlPressed, setCtrlPressed] = useState(false)
|
const [ctrlPressed, setCtrlPressed] = useState(false)
|
||||||
const [webout, setWebout] = useState('')
|
const [webout, setWebout] = useState('')
|
||||||
const [tab, setTab] = React.useState('1')
|
const [tab, setTab] = useState('1')
|
||||||
|
const [selectedRunTime, setSelectedRunTime] = useState(RunTimeType.SAS)
|
||||||
|
|
||||||
const handleTabChange = (_e: any, newValue: string) => {
|
const handleTabChange = (_e: any, newValue: string) => {
|
||||||
setTab(newValue)
|
setTab(newValue)
|
||||||
@@ -57,7 +70,7 @@ const Studio = () => {
|
|||||||
|
|
||||||
const runCode = (code: string) => {
|
const runCode = (code: string) => {
|
||||||
axios
|
axios
|
||||||
.post(`/SASjsApi/code/execute`, { code })
|
.post(`/SASjsApi/code/execute`, { code, runTime: selectedRunTime })
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const parsedLog = res?.data?.log
|
const parsedLog = res?.data?.log
|
||||||
.map((logLine: any) => logLine.line)
|
.map((logLine: any) => logLine.line)
|
||||||
@@ -89,6 +102,10 @@ const Studio = () => {
|
|||||||
if (!event.ctrlKey && ctrlPressed) setCtrlPressed(false)
|
if (!event.ctrlKey && ctrlPressed) setCtrlPressed(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleChangeRunTime = (event: SelectChangeEvent) => {
|
||||||
|
setSelectedRunTime(event.target.value as RunTimeType)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const content = localStorage.getItem('fileContent') ?? ''
|
const content = localStorage.getItem('fileContent') ?? ''
|
||||||
setFileContent(content)
|
setFileContent(content)
|
||||||
@@ -149,8 +166,21 @@ const Studio = () => {
|
|||||||
<span style={{ fontSize: '12px' }}>RUN</span>
|
<span style={{ fontSize: '12px' }}>RUN</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<Box sx={{ minWidth: 75 }}>
|
||||||
|
<FormControl variant="standard">
|
||||||
|
<Select
|
||||||
|
labelId="run-time-select-label"
|
||||||
|
id="run-time-select"
|
||||||
|
value={selectedRunTime}
|
||||||
|
onChange={handleChangeRunTime}
|
||||||
|
>
|
||||||
|
{appContext.runTimes.map((runTime) => (
|
||||||
|
<MenuItem value={runTime}>{runTime}</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
{/* <Toolbar /> */}
|
|
||||||
<Paper
|
<Paper
|
||||||
sx={{
|
sx={{
|
||||||
height: 'calc(100vh - 170px)',
|
height: 'calc(100vh - 170px)',
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ export enum ModeType {
|
|||||||
Desktop = 'desktop'
|
Desktop = 'desktop'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum RunTimeType {
|
||||||
|
SAS = 'sas',
|
||||||
|
JS = 'js'
|
||||||
|
}
|
||||||
|
|
||||||
interface AppContextProps {
|
interface AppContextProps {
|
||||||
checkingSession: boolean
|
checkingSession: boolean
|
||||||
loggedIn: boolean
|
loggedIn: boolean
|
||||||
@@ -25,6 +30,7 @@ interface AppContextProps {
|
|||||||
displayName: string
|
displayName: string
|
||||||
setDisplayName: Dispatch<SetStateAction<string>> | null
|
setDisplayName: Dispatch<SetStateAction<string>> | null
|
||||||
mode: ModeType
|
mode: ModeType
|
||||||
|
runTimes: RunTimeType[]
|
||||||
logout: (() => void) | null
|
logout: (() => void) | null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +45,7 @@ export const AppContext = createContext<AppContextProps>({
|
|||||||
displayName: '',
|
displayName: '',
|
||||||
setDisplayName: null,
|
setDisplayName: null,
|
||||||
mode: ModeType.Server,
|
mode: ModeType.Server,
|
||||||
|
runTimes: [],
|
||||||
logout: null
|
logout: null
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -50,6 +57,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
|
|||||||
const [username, setUsername] = useState('')
|
const [username, setUsername] = useState('')
|
||||||
const [displayName, setDisplayName] = useState('')
|
const [displayName, setDisplayName] = useState('')
|
||||||
const [mode, setMode] = useState(ModeType.Server)
|
const [mode, setMode] = useState(ModeType.Server)
|
||||||
|
const [runTimes, setRunTimes] = useState<RunTimeType[]>([])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCheckingSession(true)
|
setCheckingSession(true)
|
||||||
@@ -74,6 +82,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
|
|||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
.then((data: any) => {
|
.then((data: any) => {
|
||||||
setMode(data.mode)
|
setMode(data.mode)
|
||||||
|
setRunTimes(data.runTimes)
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
}, [])
|
}, [])
|
||||||
@@ -99,6 +108,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
|
|||||||
displayName,
|
displayName,
|
||||||
setDisplayName,
|
setDisplayName,
|
||||||
mode,
|
mode,
|
||||||
|
runTimes,
|
||||||
logout
|
logout
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user