1
0
mirror of https://github.com/sasjs/adapter.git synced 2026-01-06 04:00:05 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Saad Jutt
66061c6471 fix(loginPrompt): z-index added 2021-09-10 20:41:43 +05:00
29 changed files with 1061 additions and 1945 deletions

View File

@@ -1,7 +1,7 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: npm - package-ecosystem: npm
directory: '/' directory: "/"
schedule: schedule:
interval: monthly interval: daily
open-pull-requests-limit: 10 open-pull-requests-limit: 10

2
.gitignore vendored
View File

@@ -5,4 +5,4 @@ build
/coverage /coverage
.DS_Store .DS_Store

View File

@@ -3,4 +3,3 @@ docs/
.github/ .github/
*.md *.md
*.spec.ts *.spec.ts
.all-contributorsrc

View File

@@ -36,7 +36,7 @@ Ok ok. Deploy this [example.html](https://raw.githubusercontent.com/sasjs/adapte
The backend part can be deployed as follows: The backend part can be deployed as follows:
```sas ```
%let appLoc=/Public/app/readme; /* Metadata or Viya Folder per SASjs config */ %let appLoc=/Public/app/readme; /* Metadata or Viya Folder per SASjs config */
filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas"; filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
%inc mc; /* compile macros (can also be downloaded & compiled seperately) */ %inc mc; /* compile macros (can also be downloaded & compiled seperately) */
@@ -85,11 +85,11 @@ let sasJs = new SASjs.default(
); );
``` ```
If you've installed it via NPM, you can import it as a default import like so: If you've installed it via NPM, you can import it as a default import like so:
```js ```
import SASjs from '@sasjs/adapter'; import SASjs from '@sasjs/adapter';
``` ```
You can then instantiate it with: You can then instantiate it with:
```js ```
const sasJs = new SASjs({your config}) const sasJs = new SASjs({your config})
``` ```
@@ -119,7 +119,6 @@ sasJs.request("/path/to/my/service", dataObject)
console.log(response.tablewith2cols1row[0].COL1.value) console.log(response.tablewith2cols1row[0].COL1.value)
}) })
``` ```
We supply the path to the SAS service, and a data object. The data object can be null (for services with no input), or can contain one or more tables in the following format: We supply the path to the SAS service, and a data object. The data object can be null (for services with no input), or can contain one or more tables in the following format:
```javascript ```javascript
@@ -147,7 +146,6 @@ The adapter will also cache the logs (if debug enabled) and even the work tables
The SAS side is handled by a number of macros in the [macro core](https://github.com/sasjs/core) library. The SAS side is handled by a number of macros in the [macro core](https://github.com/sasjs/core) library.
The following snippet shows the process of SAS tables arriving / leaving: The following snippet shows the process of SAS tables arriving / leaving:
```sas ```sas
/* fetch all input tables sent from frontend - they arrive as work tables */ /* fetch all input tables sent from frontend - they arrive as work tables */
%webout(FETCH) %webout(FETCH)
@@ -163,6 +161,7 @@ run;
%webout(OBJ,tables,fmt=N) /* unformatted (raw) data */ %webout(OBJ,tables,fmt=N) /* unformatted (raw) data */
%webout(OBJ,tables,label=newtable) /* rename tables on export */ %webout(OBJ,tables,label=newtable) /* rename tables on export */
%webout(CLOSE) /* close the JSON and send some extra useful variables too */ %webout(CLOSE) /* close the JSON and send some extra useful variables too */
``` ```
## Configuration ## Configuration
@@ -173,7 +172,6 @@ Configuration on the client side involves passing an object on startup, which ca
* `serverType` - either `SAS9` or `SASVIYA`. * `serverType` - either `SAS9` or `SASVIYA`.
* `serverUrl` - the location (including http protocol and port) of the SAS Server. Can be omitted, eg if serving directly from the SAS Web Server, or in streaming mode. * `serverUrl` - the location (including http protocol and port) of the SAS Server. Can be omitted, eg if serving directly from the SAS Web Server, or in streaming mode.
* `debug` - if `true` then SAS Logs and extra debug information is returned. * `debug` - if `true` then SAS Logs and extra debug information is returned.
* `LoginMechanism` - either `Default` or `Redirected`. If `Redirected` then authentication occurs through the injection of an additional screen, which contains the SASLogon prompt. This allows for more complex authentication flows (such as 2FA) and avoids the need to handle passwords in the application itself. The styling of the redirect flow can also be modified. If left at "Default" then the developer must capture the username and password and use these with the `.login()` method.
* `useComputeApi` - Only relevant when the serverType is `SASVIYA`. If `true` the [Compute API](#using-the-compute-api) is used. If `false` the [JES API](#using-the-jes-api) is used. If `null` or `undefined` the [Web](#using-jes-web-app) approach is used. * `useComputeApi` - Only relevant when the serverType is `SASVIYA`. If `true` the [Compute API](#using-the-compute-api) is used. If `false` the [JES API](#using-the-jes-api) is used. If `null` or `undefined` the [Web](#using-jes-web-app) approach is used.
* `contextName` - Compute context on which the requests will be called. If missing or not provided, defaults to `Job Execution Compute context`. * `contextName` - Compute context on which the requests will be called. If missing or not provided, defaults to `Job Execution Compute context`.
@@ -198,7 +196,7 @@ Here we are running Jobs using the Job Execution Service except this time we are
This approach (`useComputeApi: false`) also ensures that jobs are displayed in Environment Manager. This approach (`useComputeApi: false`) also ensures that jobs are displayed in Environment Manager.
```json ```
{ {
appLoc:"/Your/Path", appLoc:"/Your/Path",
serverType:"SASVIYA", serverType:"SASVIYA",
@@ -212,12 +210,12 @@ This approach is by far the fastest, as a result of the optimisations we have bu
With this approach (`useComputeApi: true`), the requests/logs will _not_ appear in the list in Environment manager. With this approach (`useComputeApi: true`), the requests/logs will _not_ appear in the list in Environment manager.
```json ```
{ {
appLoc:"/Your/Path", appLoc:"/Your/Path",
serverType:"SASVIYA", serverType:"SASVIYA",
useComputeApi: true, useComputeApi: true,
contextName: "yourComputeContext" contextName: 'yourComputeContext'
} }
``` ```

2144
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -48,29 +48,29 @@
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"cp": "^0.2.0", "cp": "^0.2.0",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"jest": "^27.2.0", "jest": "^27.1.0",
"jest-extended": "^0.11.5", "jest-extended": "^0.11.5",
"node-polyfill-webpack-plugin": "^1.1.4", "node-polyfill-webpack-plugin": "^1.1.4",
"path": "^0.12.7", "path": "^0.12.7",
"process": "^0.11.10", "process": "^0.11.10",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"semantic-release": "^17.4.7", "semantic-release": "^17.4.7",
"terser-webpack-plugin": "^5.2.4", "terser-webpack-plugin": "^5.2.0",
"ts-jest": "^27.0.3", "ts-jest": "^27.0.3",
"ts-loader": "^9.2.2", "ts-loader": "^9.2.2",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0", "tslint-config-prettier": "^1.18.0",
"typedoc": "^0.22.3", "typedoc": "^0.21.9",
"typedoc-neo-theme": "^1.1.1", "typedoc-neo-theme": "^1.1.1",
"typedoc-plugin-external-module-name": "^4.0.6", "typedoc-plugin-external-module-name": "^4.0.6",
"typescript": "4.3.5", "typescript": "4.3.5",
"webpack": "^5.52.1", "webpack": "^5.44.0",
"webpack-cli": "^4.7.2" "webpack-cli": "^4.7.2"
}, },
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@sasjs/utils": "^2.32.0", "@sasjs/utils": "^2.30.0",
"axios": "^0.21.4", "axios": "^0.21.1",
"axios-cookiejar-support": "^1.0.1", "axios-cookiejar-support": "^1.0.1",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"https": "^1.0.0", "https": "^1.0.0",

View File

@@ -5,7 +5,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@sasjs/adapter": "file:../build/sasjs-adapter-5.0.0.tgz", "@sasjs/adapter": "file:../build/sasjs-adapter-5.0.0.tgz",
"@sasjs/test-framework": "^1.4.2", "@sasjs/test-framework": "^1.4.0",
"@types/jest": "^26.0.20", "@types/jest": "^26.0.20",
"@types/node": "^14.14.41", "@types/node": "^14.14.41",
"@types/react": "^17.0.1", "@types/react": "^17.0.1",

View File

@@ -78,8 +78,8 @@ export const basicTests = (
'common/sendArr', 'common/sendArr',
stringData, stringData,
undefined, undefined,
async () => { () => {
await adapter.logIn(userName, password) adapter.logIn(userName, password)
} }
) )
}, },

98
src/FileUploader.ts Normal file
View File

@@ -0,0 +1,98 @@
import { isUrl, getValidJson, parseSasViyaDebugResponse } from './utils'
import { UploadFile } from './types/UploadFile'
import { ErrorResponse, LoginRequiredError } from './types/errors'
import { RequestClient } from './request/RequestClient'
import { ServerType } from '@sasjs/utils/types'
import SASjs from './SASjs'
import { Server } from 'https'
import { SASjsConfig } from './types'
import { config } from 'process'
export class FileUploader {
constructor(
private sasjsConfig: SASjsConfig,
private jobsPath: string,
private requestClient: RequestClient
) {
if (this.sasjsConfig.serverUrl) isUrl(this.sasjsConfig.serverUrl)
}
public uploadFile(sasJob: string, files: UploadFile[], params: any) {
if (files?.length < 1)
return Promise.reject(
new ErrorResponse('At least one file must be provided.')
)
if (!sasJob || sasJob === '')
return Promise.reject(new ErrorResponse('sasJob must be provided.'))
let paramsString = ''
for (let param in params) {
if (params.hasOwnProperty(param)) {
paramsString += `&${param}=${params[param]}`
}
}
const program = this.sasjsConfig.appLoc
? this.sasjsConfig.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
: sasJob
const uploadUrl = `${this.jobsPath}/?${
'_program=' + program
}${paramsString}`
const formData = new FormData()
for (let file of files) {
formData.append('file', file.file, file.fileName)
}
const csrfToken = this.requestClient.getCsrfToken('file')
if (csrfToken) formData.append('_csrf', csrfToken.value)
if (this.sasjsConfig.debug) formData.append('_debug', '131')
if (
this.sasjsConfig.serverType === ServerType.SasViya &&
this.sasjsConfig.contextName
)
formData.append('_contextname', this.sasjsConfig.contextName)
const headers = {
'cache-control': 'no-cache',
Accept: '*/*',
'Content-Type': 'text/plain'
}
// currently only web approach is supported for file upload
// therefore log is part of response with debug enabled and must be parsed
return this.requestClient
.post(uploadUrl, formData, undefined, 'application/json', headers)
.then(async (res) => {
if (
this.sasjsConfig.serverType === ServerType.SasViya &&
this.sasjsConfig.debug
) {
const jsonResponse = await parseSasViyaDebugResponse(
res.result as string,
this.requestClient,
this.sasjsConfig.serverUrl
)
return jsonResponse
}
return typeof res.result === 'string'
? getValidJson(res.result)
: res.result
//TODO: append to SASjs requests
})
.catch((err: Error) => {
if (err instanceof LoginRequiredError) {
return Promise.reject(
new ErrorResponse('You must be logged in to upload a file.', err)
)
}
return Promise.reject(
new ErrorResponse('File upload request failed.', err)
)
})
}
}

View File

@@ -51,16 +51,6 @@ export class SASViyaApiClient {
) )
private folderMap = new Map<string, Job[]>() private folderMap = new Map<string, Job[]>()
/**
* A helper method used to call appendRequest method of RequestClient
* @param response - response from sasjs request
* @param program - name of program
* @param debug - a boolean that indicates whether debug was enabled or not
*/
public appendRequest(response: any, program: string, debug: boolean) {
this.requestClient!.appendRequest(response, program, debug)
}
public get debug() { public get debug() {
return this._debug return this._debug
} }

View File

@@ -4,14 +4,11 @@ import {
UploadFile, UploadFile,
EditContextInput, EditContextInput,
PollOptions, PollOptions,
LoginMechanism, LoginMechanism
FolderMember,
ServiceMember,
ExecutionQuery
} from './types' } from './types'
import { SASViyaApiClient } from './SASViyaApiClient' import { SASViyaApiClient } from './SASViyaApiClient'
import { SAS9ApiClient } from './SAS9ApiClient' import { SAS9ApiClient } from './SAS9ApiClient'
import { SASjsApiClient } from './SASjsApiClient' import { FileUploader } from './FileUploader'
import { AuthManager } from './auth' import { AuthManager } from './auth'
import { import {
ServerType, ServerType,
@@ -25,8 +22,7 @@ import {
WebJobExecutor, WebJobExecutor,
ComputeJobExecutor, ComputeJobExecutor,
JesJobExecutor, JesJobExecutor,
Sas9JobExecutor, Sas9JobExecutor
FileUploader
} from './job-execution' } from './job-execution'
import { ErrorResponse } from './types/errors' import { ErrorResponse } from './types/errors'
import { LoginOptions, LoginResult } from './types/Login' import { LoginOptions, LoginResult } from './types/Login'
@@ -53,7 +49,6 @@ export default class SASjs {
private jobsPath: string = '' private jobsPath: string = ''
private sasViyaApiClient: SASViyaApiClient | null = null private sasViyaApiClient: SASViyaApiClient | null = null
private sas9ApiClient: SAS9ApiClient | null = null private sas9ApiClient: SAS9ApiClient | null = null
private SASjsApiClient: SASjsApiClient | null = null
private fileUploader: FileUploader | null = null private fileUploader: FileUploader | null = null
private authManager: AuthManager | null = null private authManager: AuthManager | null = null
private requestClient: RequestClient | null = null private requestClient: RequestClient | null = null
@@ -512,7 +507,7 @@ export default class SASjs {
...this.sasjsConfig, ...this.sasjsConfig,
...config ...config
} }
this.setupConfiguration() await this.setupConfiguration()
} }
/** /**
@@ -576,32 +571,24 @@ export default class SASjs {
* Process). Is prepended at runtime with the value of `appLoc`. * Process). Is prepended at runtime with the value of `appLoc`.
* @param files - array of files to be uploaded, including File object and file name. * @param files - array of files to be uploaded, including File object and file name.
* @param params - request URL parameters. * @param params - request URL parameters.
* @param config - provide any changes to the config here, for instance to * @param overrideSasjsConfig - object to override existing config (optional)
* enable/disable `debug`. Any change provided will override the global config,
* for that particular function call.
* @param loginRequiredCallback - a function that is called if the
* user is not logged in (eg to display a login form). The request will be
* resubmitted after successful login.
*/ */
public async uploadFile( public uploadFile(
sasJob: string, sasJob: string,
files: UploadFile[], files: UploadFile[],
params: { [key: string]: any } | null, params: any,
config: { [key: string]: any } = {}, overrideSasjsConfig?: any
loginRequiredCallback?: () => any
) { ) {
config = { const fileUploader = overrideSasjsConfig
...this.sasjsConfig, ? new FileUploader(
...config { ...this.sasjsConfig, ...overrideSasjsConfig },
} this.jobsPath,
const data = { files, params } this.requestClient!
)
: this.fileUploader ||
new FileUploader(this.sasjsConfig, this.jobsPath, this.requestClient!)
return await this.fileUploader!.execute( return fileUploader.uploadFile(sasJob, files, params)
sasJob,
data,
config,
loginRequiredCallback
)
} }
/** /**
@@ -829,14 +816,6 @@ export default class SASjs {
) )
} }
public async deployToSASjs(members: [FolderMember, ServiceMember]) {
return await this.SASjsApiClient?.deploy(members, this.sasjsConfig.appLoc)
}
public async executeJobSASjs(query: ExecutionQuery) {
return await this.SASjsApiClient?.executeJob(query)
}
/** /**
* Kicks off execution of the given job via the compute API. * Kicks off execution of the given job via the compute API.
* @returns an object representing the compute session created for the given job. * @returns an object representing the compute session created for the given job.
@@ -895,7 +874,6 @@ export default class SASjs {
await this.webJobExecutor?.resendWaitingRequests() await this.webJobExecutor?.resendWaitingRequests()
await this.computeJobExecutor?.resendWaitingRequests() await this.computeJobExecutor?.resendWaitingRequests()
await this.jesJobExecutor?.resendWaitingRequests() await this.jesJobExecutor?.resendWaitingRequests()
await this.fileUploader?.resendWaitingRequests()
} }
/** /**
@@ -927,18 +905,20 @@ export default class SASjs {
}) })
} }
/**
* this method returns an array of SASjsRequest
* @returns SASjsRequest[]
*/
public getSasRequests() { public getSasRequests() {
const requests = [...this.requestClient!.getRequests()] const requests = [
...this.webJobExecutor!.getRequests(),
...this.computeJobExecutor!.getRequests(),
...this.jesJobExecutor!.getRequests()
]
const sortedRequests = requests.sort(compareTimestamps) const sortedRequests = requests.sort(compareTimestamps)
return sortedRequests return sortedRequests
} }
public clearSasRequests() { public clearSasRequests() {
this.requestClient!.clearRequests() this.webJobExecutor!.clearRequests()
this.computeJobExecutor!.clearRequests()
this.jesJobExecutor!.clearRequests()
} }
private setupConfiguration() { private setupConfiguration() {
@@ -961,17 +941,10 @@ export default class SASjs {
this.sasjsConfig.serverUrl = this.sasjsConfig.serverUrl.slice(0, -1) this.sasjsConfig.serverUrl = this.sasjsConfig.serverUrl.slice(0, -1)
} }
if (!this.requestClient) { this.requestClient = new RequestClient(
this.requestClient = new RequestClient( this.sasjsConfig.serverUrl,
this.sasjsConfig.serverUrl, this.sasjsConfig.allowInsecureRequests
this.sasjsConfig.allowInsecureRequests )
)
} else {
this.requestClient.setConfig(
this.sasjsConfig.serverUrl,
this.sasjsConfig.allowInsecureRequests
)
}
this.jobsPath = this.jobsPath =
this.sasjsConfig.serverType === ServerType.SasViya this.sasjsConfig.serverType === ServerType.SasViya
@@ -986,49 +959,34 @@ export default class SASjs {
) )
if (this.sasjsConfig.serverType === ServerType.SasViya) { if (this.sasjsConfig.serverType === ServerType.SasViya) {
if (this.sasViyaApiClient) { if (this.sasViyaApiClient)
this.sasViyaApiClient!.setConfig( this.sasViyaApiClient!.setConfig(
this.sasjsConfig.serverUrl, this.sasjsConfig.serverUrl,
this.sasjsConfig.appLoc this.sasjsConfig.appLoc
) )
} else { else
this.sasViyaApiClient = new SASViyaApiClient( this.sasViyaApiClient = new SASViyaApiClient(
this.sasjsConfig.serverUrl, this.sasjsConfig.serverUrl,
this.sasjsConfig.appLoc, this.sasjsConfig.appLoc,
this.sasjsConfig.contextName, this.sasjsConfig.contextName,
this.requestClient this.requestClient
) )
}
this.sasViyaApiClient.debug = this.sasjsConfig.debug this.sasViyaApiClient.debug = this.sasjsConfig.debug
} }
if (this.sasjsConfig.serverType === ServerType.Sas9) { if (this.sasjsConfig.serverType === ServerType.Sas9) {
if (this.sas9ApiClient) { if (this.sas9ApiClient)
this.sas9ApiClient!.setConfig(this.sasjsConfig.serverUrl) this.sas9ApiClient!.setConfig(this.sasjsConfig.serverUrl)
} else { else
this.sas9ApiClient = new SAS9ApiClient( this.sas9ApiClient = new SAS9ApiClient(
this.sasjsConfig.serverUrl, this.sasjsConfig.serverUrl,
this.jobsPath, this.jobsPath,
this.sasjsConfig.allowInsecureRequests this.sasjsConfig.allowInsecureRequests
) )
}
}
if (this.sasjsConfig.serverType === ServerType.Sasjs) {
if (this.SASjsApiClient) {
this.SASjsApiClient.setConfig(this.sasjsConfig.serverUrl)
} else {
this.SASjsApiClient = new SASjsApiClient(
this.sasjsConfig.serverUrl,
this.requestClient
)
}
} }
this.fileUploader = new FileUploader( this.fileUploader = new FileUploader(
this.sasjsConfig.serverUrl, this.sasjsConfig,
this.sasjsConfig.serverType!,
this.jobsPath, this.jobsPath,
this.requestClient this.requestClient
) )

View File

@@ -1,39 +0,0 @@
import { FolderMember, ServiceMember, ExecutionQuery } from './types'
import { RequestClient } from './request/RequestClient'
export class SASjsApiClient {
constructor(
private serverUrl: string,
private requestClient: RequestClient
) {}
public setConfig(serverUrl: string) {
if (serverUrl) this.serverUrl = serverUrl
}
public async deploy(members: [FolderMember, ServiceMember], appLoc: string) {
const { result } = await this.requestClient.post<{
status: string
message: string
example?: {}
}>(
'SASjsApi/drive/deploy',
{ fileTree: members, appLoc: appLoc },
undefined
)
return Promise.resolve(result)
}
public async executeJob(query: ExecutionQuery) {
const { result } = await this.requestClient.post<{
status: string
message: string
log?: string
logPath?: string
error?: {}
}>('SASjsApi/stp/execute', query, undefined)
return Promise.resolve(result)
}
}

View File

@@ -256,8 +256,6 @@ export class AuthManager {
.split(' ') .split(' ')
.map((name: string) => name.slice(0, 3).toLowerCase()) .map((name: string) => name.slice(0, 3).toLowerCase())
.join('') .join('')
default:
return ''
} }
} }

View File

@@ -35,16 +35,19 @@ export class ComputeJobExecutor extends BaseJobExecutor {
expectWebout expectWebout
) )
.then((response) => { .then((response) => {
this.sasViyaApiClient.appendRequest(response, sasJob, config.debug) this.appendRequest(response, sasJob, config.debug)
resolve(response.result) resolve(response.result)
}) })
.catch(async (e: Error) => { .catch(async (e: Error) => {
if (e instanceof ComputeJobExecutionError) { if (e instanceof ComputeJobExecutionError) {
this.sasViyaApiClient.appendRequest(e, sasJob, config.debug) this.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }
if (e instanceof LoginRequiredError) { if (e instanceof LoginRequiredError) {
await loginCallback()
this.appendWaitingRequest(() => { this.appendWaitingRequest(() => {
return this.execute( return this.execute(
sasJob, sasJob,
@@ -60,8 +63,6 @@ export class ComputeJobExecutor extends BaseJobExecutor {
} }
) )
}) })
await loginCallback()
} else { } else {
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }

View File

@@ -1,143 +0,0 @@
import {
getValidJson,
parseSasViyaDebugResponse,
parseWeboutResponse
} from '../utils'
import { UploadFile } from '../types/UploadFile'
import {
ErrorResponse,
JobExecutionError,
LoginRequiredError
} from '../types/errors'
import { RequestClient } from '../request/RequestClient'
import { ServerType } from '@sasjs/utils/types'
import { BaseJobExecutor } from './JobExecutor'
interface dataFileUpload {
files: UploadFile[]
params: { [key: string]: any } | null
}
export class FileUploader extends BaseJobExecutor {
constructor(
serverUrl: string,
serverType: ServerType,
private jobsPath: string,
private requestClient: RequestClient
) {
super(serverUrl, serverType)
}
public async execute(
sasJob: string,
data: any,
config: any,
loginRequiredCallback?: any
) {
const { files, params }: dataFileUpload = data
const loginCallback = loginRequiredCallback || (() => Promise.resolve())
if (!files?.length)
throw new ErrorResponse('At least one file must be provided.')
if (!sasJob || sasJob === '')
throw new ErrorResponse('sasJob must be provided.')
let paramsString = ''
for (let param in params)
if (params.hasOwnProperty(param))
paramsString += `&${param}=${params[param]}`
const program = config.appLoc
? config.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '')
: sasJob
const uploadUrl = `${this.jobsPath}/?${
'_program=' + program
}${paramsString}`
const formData = new FormData()
for (let file of files) {
formData.append('file', file.file, file.fileName)
}
const csrfToken = this.requestClient.getCsrfToken('file')
if (csrfToken) formData.append('_csrf', csrfToken.value)
if (config.debug) formData.append('_debug', '131')
if (config.serverType === ServerType.SasViya && config.contextName)
formData.append('_contextname', config.contextName)
const headers = {
'cache-control': 'no-cache',
Accept: '*/*',
'Content-Type': 'text/plain'
}
// currently only web approach is supported for file upload
// therefore log is part of response with debug enabled and must be parsed
const requestPromise = new Promise((resolve, reject) => {
this.requestClient
.post(uploadUrl, formData, undefined, 'application/json', headers)
.then(async (res: any) => {
this.requestClient.appendRequest(res, sasJob, config.debug)
let jsonResponse = res.result
if (config.debug) {
switch (this.serverType) {
case ServerType.SasViya:
jsonResponse = await parseSasViyaDebugResponse(
res.result,
this.requestClient,
config.serverUrl
)
break
case ServerType.Sas9:
jsonResponse =
typeof res.result === 'string'
? parseWeboutResponse(res.result, uploadUrl)
: res.result
break
}
} else {
jsonResponse =
typeof res.result === 'string'
? getValidJson(res.result)
: res.result
}
resolve(jsonResponse)
})
.catch(async (e: Error) => {
if (e instanceof JobExecutionError) {
this.requestClient!.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e))
}
if (e instanceof LoginRequiredError) {
this.appendWaitingRequest(() => {
return this.execute(
sasJob,
data,
config,
loginRequiredCallback
).then(
(res: any) => {
resolve(res)
},
(err: any) => {
reject(err)
}
)
})
await loginCallback()
} else {
reject(new ErrorResponse('File upload request failed.', e))
}
})
})
return requestPromise
}
}

View File

@@ -28,7 +28,7 @@ export class JesJobExecutor extends BaseJobExecutor {
this.sasViyaApiClient this.sasViyaApiClient
?.executeJob(sasJob, config.contextName, config.debug, data, authConfig) ?.executeJob(sasJob, config.contextName, config.debug, data, authConfig)
.then((response: any) => { .then((response: any) => {
this.sasViyaApiClient.appendRequest(response, sasJob, config.debug) this.appendRequest(response, sasJob, config.debug)
const responseObject = appendExtraResponseAttributes( const responseObject = appendExtraResponseAttributes(
response, response,
@@ -39,12 +39,14 @@ export class JesJobExecutor extends BaseJobExecutor {
}) })
.catch(async (e: Error) => { .catch(async (e: Error) => {
if (e instanceof JobExecutionError) { if (e instanceof JobExecutionError) {
this.sasViyaApiClient.appendRequest(e, sasJob, config.debug) this.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }
if (e instanceof LoginRequiredError) { if (e instanceof LoginRequiredError) {
await loginCallback()
this.appendWaitingRequest(() => { this.appendWaitingRequest(() => {
return this.execute( return this.execute(
sasJob, sasJob,
@@ -62,8 +64,6 @@ export class JesJobExecutor extends BaseJobExecutor {
} }
) )
}) })
await loginCallback()
} else { } else {
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }

View File

@@ -1,6 +1,7 @@
import { AuthConfig, ServerType } from '@sasjs/utils/types' import { AuthConfig, ServerType } from '@sasjs/utils/types'
import { SASjsRequest } from '../types'
import { ExtraResponseAttributes } from '@sasjs/utils/types' import { ExtraResponseAttributes } from '@sasjs/utils/types'
import { asyncForEach } from '../utils' import { asyncForEach, parseGeneratedCode, parseSourceCode } from '../utils'
export type ExecuteFunction = () => Promise<any> export type ExecuteFunction = () => Promise<any>
@@ -14,12 +15,15 @@ export interface JobExecutor {
extraResponseAttributes?: ExtraResponseAttributes[] extraResponseAttributes?: ExtraResponseAttributes[]
) => Promise<any> ) => Promise<any>
resendWaitingRequests: () => Promise<void> resendWaitingRequests: () => Promise<void>
getRequests: () => SASjsRequest[]
clearRequests: () => void
} }
export abstract class BaseJobExecutor implements JobExecutor { export abstract class BaseJobExecutor implements JobExecutor {
constructor(protected serverUrl: string, protected serverType: ServerType) {} constructor(protected serverUrl: string, protected serverType: ServerType) {}
private waitingRequests: ExecuteFunction[] = [] private waitingRequests: ExecuteFunction[] = []
private requests: SASjsRequest[] = []
abstract execute( abstract execute(
sasJob: string, sasJob: string,
@@ -42,7 +46,54 @@ export abstract class BaseJobExecutor implements JobExecutor {
return return
} }
getRequests = () => this.requests
clearRequests = () => {
this.requests = []
}
protected appendWaitingRequest(request: ExecuteFunction) { protected appendWaitingRequest(request: ExecuteFunction) {
this.waitingRequests.push(request) this.waitingRequests.push(request)
} }
protected appendRequest(response: any, program: string, debug: boolean) {
let sourceCode = ''
let generatedCode = ''
let sasWork = null
if (debug) {
if (response?.log) {
sourceCode = parseSourceCode(response.log)
generatedCode = parseGeneratedCode(response.log)
if (response?.result) {
sasWork = response.result.WORK
} else {
sasWork = response.log
}
} else if (response?.result) {
sourceCode = parseSourceCode(response.result)
generatedCode = parseGeneratedCode(response.result)
sasWork = response.result.WORK
}
}
const stringifiedResult =
typeof response?.result === 'string'
? response?.result
: JSON.stringify(response?.result, null, 2)
this.requests.push({
logFile: response?.log || stringifiedResult || response,
serviceLink: program,
timestamp: new Date(),
sourceCode,
generatedCode,
SASWORK: sasWork
})
if (this.requests.length > 20) {
this.requests.splice(0, 1)
}
}
} }

View File

@@ -45,7 +45,7 @@ export class Sas9JobExecutor extends BaseJobExecutor {
if (data) { if (data) {
try { try {
formData = generateFileUploadForm(formData, data) formData = generateFileUploadForm(formData, data)
} catch (e: any) { } catch (e) {
return Promise.reject(new ErrorResponse(e?.message, e)) return Promise.reject(new ErrorResponse(e?.message, e))
} }
} }

View File

@@ -53,36 +53,7 @@ export class WebJobExecutor extends BaseJobExecutor {
let apiUrl = `${config.serverUrl}${this.jobsPath}/?${'_program=' + program}` let apiUrl = `${config.serverUrl}${this.jobsPath}/?${'_program=' + program}`
if (config.serverType === ServerType.SasViya) { if (config.serverType === ServerType.SasViya) {
let jobUri const jobUri = await this.getJobUri(sasJob)
try {
jobUri = await this.getJobUri(sasJob)
} catch (e: any) {
return new Promise(async (resolve, reject) => {
if (e instanceof LoginRequiredError) {
this.appendWaitingRequest(() => {
return this.execute(
sasJob,
data,
config,
loginRequiredCallback,
authConfig,
extraResponseAttributes
).then(
(res: any) => {
resolve(res)
},
(err: any) => {
reject(err)
}
)
})
await loginCallback()
} else {
reject(new ErrorResponse(e?.message, e))
}
})
}
apiUrl += jobUri.length > 0 ? '&_job=' + jobUri : '' apiUrl += jobUri.length > 0 ? '&_job=' + jobUri : ''
@@ -119,7 +90,7 @@ export class WebJobExecutor extends BaseJobExecutor {
// file upload approach // file upload approach
try { try {
formData = generateFileUploadForm(formData, data) formData = generateFileUploadForm(formData, data)
} catch (e: any) { } catch (e) {
return Promise.reject(new ErrorResponse(e?.message, e)) return Promise.reject(new ErrorResponse(e?.message, e))
} }
} else { } else {
@@ -129,7 +100,7 @@ export class WebJobExecutor extends BaseJobExecutor {
generateTableUploadForm(formData, data) generateTableUploadForm(formData, data)
formData = newFormData formData = newFormData
requestParams = { ...requestParams, ...params } requestParams = { ...requestParams, ...params }
} catch (e: any) { } catch (e) {
return Promise.reject(new ErrorResponse(e?.message, e)) return Promise.reject(new ErrorResponse(e?.message, e))
} }
} }
@@ -144,8 +115,6 @@ export class WebJobExecutor extends BaseJobExecutor {
const requestPromise = new Promise((resolve, reject) => { const requestPromise = new Promise((resolve, reject) => {
this.requestClient!.post(apiUrl, formData, undefined) this.requestClient!.post(apiUrl, formData, undefined)
.then(async (res: any) => { .then(async (res: any) => {
this.requestClient!.appendRequest(res, sasJob, config.debug)
let jsonResponse = res.result let jsonResponse = res.result
if (config.debug) { if (config.debug) {
@@ -166,6 +135,8 @@ export class WebJobExecutor extends BaseJobExecutor {
} }
} }
this.appendRequest(res, sasJob, config.debug)
const responseObject = appendExtraResponseAttributes( const responseObject = appendExtraResponseAttributes(
{ result: jsonResponse }, { result: jsonResponse },
extraResponseAttributes extraResponseAttributes
@@ -174,7 +145,8 @@ export class WebJobExecutor extends BaseJobExecutor {
}) })
.catch(async (e: Error) => { .catch(async (e: Error) => {
if (e instanceof JobExecutionError) { if (e instanceof JobExecutionError) {
this.requestClient!.appendRequest(e, sasJob, config.debug) this.appendRequest(e, sasJob, config.debug)
reject(new ErrorResponse(e?.message, e)) reject(new ErrorResponse(e?.message, e))
} }

View File

@@ -3,4 +3,3 @@ export * from './JesJobExecutor'
export * from './JobExecutor' export * from './JobExecutor'
export * from './Sas9JobExecutor' export * from './Sas9JobExecutor'
export * from './WebJobExecutor' export * from './WebJobExecutor'
export * from './FileUploader'

View File

@@ -8,11 +8,10 @@ import {
InternalServerError, InternalServerError,
JobExecutionError JobExecutionError
} from '../types/errors' } from '../types/errors'
import { SASjsRequest } from '../types'
import { parseWeboutResponse } from '../utils/parseWeboutResponse' import { parseWeboutResponse } from '../utils/parseWeboutResponse'
import { prefixMessage } from '@sasjs/utils/error' import { prefixMessage } from '@sasjs/utils/error'
import { SAS9AuthError } from '../types/errors/SAS9AuthError' import { SAS9AuthError } from '../types/errors/SAS9AuthError'
import { parseGeneratedCode, parseSourceCode } from '../utils' import { getValidJson } from '../utils'
export interface HttpClient { export interface HttpClient {
get<T>( get<T>(
@@ -48,18 +47,27 @@ export interface HttpClient {
} }
export class RequestClient implements HttpClient { export class RequestClient implements HttpClient {
private requests: SASjsRequest[] = []
protected csrfToken: CsrfToken = { headerName: '', value: '' } protected csrfToken: CsrfToken = { headerName: '', value: '' }
protected fileUploadCsrfToken: CsrfToken | undefined protected fileUploadCsrfToken: CsrfToken | undefined
protected httpClient!: AxiosInstance protected httpClient: AxiosInstance
constructor(protected baseUrl: string, allowInsecure = false) { constructor(protected baseUrl: string, allowInsecure = false) {
this.createHttpClient(baseUrl, allowInsecure) const https = require('https')
} if (allowInsecure && https.Agent) {
this.httpClient = axios.create({
baseURL: baseUrl,
httpsAgent: new https.Agent({
rejectUnauthorized: !allowInsecure
})
})
} else {
this.httpClient = axios.create({
baseURL: baseUrl
})
}
public setConfig(baseUrl: string, allowInsecure = false) { this.httpClient.defaults.validateStatus = (status) =>
this.createHttpClient(baseUrl, allowInsecure) status >= 200 && status < 305
} }
public getCsrfToken(type: 'general' | 'file' = 'general') { public getCsrfToken(type: 'general' | 'file' = 'general') {
@@ -75,66 +83,6 @@ export class RequestClient implements HttpClient {
return this.httpClient.defaults.baseURL || '' return this.httpClient.defaults.baseURL || ''
} }
/**
* this method returns all requests, an array of SASjsRequest type
* @returns SASjsRequest[]
*/
public getRequests = () => this.requests
/**
* this method clears the requests array, i.e set to empty
*/
public clearRequests = () => {
this.requests = []
}
/**
* this method appends the response from sasjs request to requests array
* @param response - response from sasjs request
* @param program - name of program
* @param debug - a boolean that indicates whether debug was enabled or not
*/
public appendRequest(response: any, program: string, debug: boolean) {
let sourceCode = ''
let generatedCode = ''
let sasWork = null
if (debug) {
if (response?.log) {
sourceCode = parseSourceCode(response.log)
generatedCode = parseGeneratedCode(response.log)
if (response?.result) {
sasWork = response.result.WORK
} else {
sasWork = response.log
}
} else if (response?.result) {
sourceCode = parseSourceCode(response.result)
generatedCode = parseGeneratedCode(response.result)
sasWork = response.result.WORK
}
}
const stringifiedResult =
typeof response?.result === 'string'
? response?.result
: JSON.stringify(response?.result, null, 2)
this.requests.push({
logFile: response?.log || stringifiedResult || response,
serviceLink: program,
timestamp: new Date(),
sourceCode,
generatedCode,
SASWORK: sasWork
})
if (this.requests.length > 20) {
this.requests.splice(0, 1)
}
}
public async get<T>( public async get<T>(
url: string, url: string,
accessToken: string | undefined, accessToken: string | undefined,
@@ -182,7 +130,7 @@ export class RequestClient implements HttpClient {
}) })
} }
public async post<T>( public post<T>(
url: string, url: string,
data: any, data: any,
accessToken: string | undefined, accessToken: string | undefined,
@@ -281,16 +229,12 @@ export class RequestClient implements HttpClient {
} }
try { try {
const response = await this.httpClient.post(url, content, { const response = await this.httpClient.post(url, content, { headers })
headers,
transformRequest: (requestBody) => requestBody
})
return { return {
result: response.data, result: response.data,
etag: response.headers['etag'] as string etag: response.headers['etag'] as string
} }
} catch (e: any) { } catch (e) {
const response = e.response as AxiosResponse const response = e.response as AxiosResponse
if (response?.status === 403 || response?.status === 449) { if (response?.status === 403 || response?.status === 449) {
this.parseAndSetFileUploadCsrfToken(response) this.parseAndSetFileUploadCsrfToken(response)
@@ -510,25 +454,6 @@ export class RequestClient implements HttpClient {
return responseToReturn return responseToReturn
} }
private createHttpClient(baseUrl: string, allowInsecure = false) {
const https = require('https')
if (allowInsecure && https.Agent) {
this.httpClient = axios.create({
baseURL: baseUrl,
httpsAgent: new https.Agent({
rejectUnauthorized: !allowInsecure
})
})
} else {
this.httpClient = axios.create({
baseURL: baseUrl
})
}
this.httpClient.defaults.validateStatus = (status) =>
status >= 200 && status < 401
}
} }
export const throwIfError = (response: AxiosResponse) => { export const throwIfError = (response: AxiosResponse) => {

View File

@@ -2,7 +2,7 @@
* @jest-environment jsdom * @jest-environment jsdom
*/ */
import { FileUploader } from '../job-execution/FileUploader' import { FileUploader } from '../FileUploader'
import { SASjsConfig, UploadFile } from '../types' import { SASjsConfig, UploadFile } from '../types'
import { RequestClient } from '../request/RequestClient' import { RequestClient } from '../request/RequestClient'
import axios from 'axios' import axios from 'axios'
@@ -34,71 +34,60 @@ const prepareFilesAndParams = () => {
describe('FileUploader', () => { describe('FileUploader', () => {
const config: SASjsConfig = { const config: SASjsConfig = {
...new SASjsConfig(), ...new SASjsConfig(),
appLoc: '/sample/apploc', appLoc: '/sample/apploc'
debug: false
} }
const fileUploader = new FileUploader( const fileUploader = new FileUploader(
config.serverUrl, config,
config.serverType!,
'/jobs/path', '/jobs/path',
new RequestClient('https://sample.server.com') new RequestClient('https://sample.server.com')
) )
it('should upload successfully', async () => { it('should upload successfully', async () => {
const sasJob = 'test/upload' const sasJob = 'test/upload'
const data = prepareFilesAndParams() const { files, params } = prepareFilesAndParams()
mockedAxios.post.mockImplementation(() => mockedAxios.post.mockImplementation(() =>
Promise.resolve({ data: sampleResponse }) Promise.resolve({ data: sampleResponse })
) )
const res = await fileUploader.execute(sasJob, data, config) const res = await fileUploader.uploadFile(sasJob, files, params)
expect(res).toEqual(JSON.parse(sampleResponse)) expect(res).toEqual(JSON.parse(sampleResponse))
}) })
it('should upload successfully when login is required', async () => {
mockedAxios.post
.mockImplementationOnce(() =>
Promise.resolve({ data: '<form action="Logon">' })
)
.mockImplementationOnce(() => Promise.resolve({ data: sampleResponse }))
const loginCallback = jest.fn().mockImplementation(async () => {
await fileUploader.resendWaitingRequests()
Promise.resolve()
})
const sasJob = 'test'
const data = prepareFilesAndParams()
const res = await fileUploader.execute(sasJob, data, config, loginCallback)
expect(res).toEqual(JSON.parse(sampleResponse))
expect(mockedAxios.post).toHaveBeenCalledTimes(2)
expect(loginCallback).toHaveBeenCalled()
})
it('should an error when no files are provided', async () => { it('should an error when no files are provided', async () => {
const sasJob = 'test/upload' const sasJob = 'test/upload'
const files: UploadFile[] = [] const files: UploadFile[] = []
const params = { table: 'libtable' } const params = { table: 'libtable' }
const res: any = await fileUploader const err = await fileUploader
.execute(sasJob, files, params, config) .uploadFile(sasJob, files, params)
.catch((err: any) => err) .catch((err: any) => err)
expect(res.error.message).toEqual('At least one file must be provided.') expect(err.error.message).toEqual('At least one file must be provided.')
}) })
it('should throw an error when no sasJob is provided', async () => { it('should throw an error when no sasJob is provided', async () => {
const sasJob = '' const sasJob = ''
const data = prepareFilesAndParams() const { files, params } = prepareFilesAndParams()
const res: any = await fileUploader const err = await fileUploader
.execute(sasJob, data, config) .uploadFile(sasJob, files, params)
.catch((err: any) => err) .catch((err: any) => err)
expect(res.error.message).toEqual('sasJob must be provided.') expect(err.error.message).toEqual('sasJob must be provided.')
})
it('should throw an error when login is required', async () => {
mockedAxios.post.mockImplementation(() =>
Promise.resolve({ data: '<form action="Logon">' })
)
const sasJob = 'test'
const { files, params } = prepareFilesAndParams()
const err = await fileUploader
.uploadFile(sasJob, files, params)
.catch((err: any) => err)
expect(err.error.message).toEqual('You must be logged in to upload a file.')
}) })
it('should throw an error when invalid JSON is returned by the server', async () => { it('should throw an error when invalid JSON is returned by the server', async () => {
@@ -107,13 +96,12 @@ describe('FileUploader', () => {
) )
const sasJob = 'test' const sasJob = 'test'
const data = prepareFilesAndParams() const { files, params } = prepareFilesAndParams()
const res: any = await fileUploader const err = await fileUploader
.execute(sasJob, data, config) .uploadFile(sasJob, files, params)
.catch((err: any) => err) .catch((err: any) => err)
expect(err.error.message).toEqual('File upload request failed.')
expect(res.error.message).toEqual('File upload request failed.')
}) })
it('should throw an error when the server request fails', async () => { it('should throw an error when the server request fails', async () => {
@@ -122,11 +110,11 @@ describe('FileUploader', () => {
) )
const sasJob = 'test' const sasJob = 'test'
const data = prepareFilesAndParams() const { files, params } = prepareFilesAndParams()
const res: any = await fileUploader const err = await fileUploader
.execute(sasJob, data, config) .uploadFile(sasJob, files, params)
.catch((err: any) => err) .catch((err: any) => err)
expect(res.error.message).toEqual('File upload request failed.') expect(err.error.message).toEqual('File upload request failed.')
}) })
}) })

View File

@@ -33,18 +33,4 @@ describe('jsonValidator', () => {
} }
expect(test).toThrow(JsonParseArrayError) expect(test).toThrow(JsonParseArrayError)
}) })
it('should throw an error when null is passed', () => {
const test = () => {
getValidJson(null as any)
}
expect(test).toThrow(InvalidJsonError)
})
it('should throw an error when undefined is passed', () => {
const test = () => {
getValidJson(undefined as any)
}
expect(test).toThrow(InvalidJsonError)
})
}) })

View File

@@ -1,5 +0,0 @@
export interface ExecutionQuery {
_program: string
_debug?: number
_log?: boolean
}

View File

@@ -1,47 +0,0 @@
export interface FileTree {
members: [FolderMember, ServiceMember]
}
export enum MemberType {
folder = 'folder',
service = 'service'
}
export interface FolderMember {
name: string
type: MemberType.folder
members: [FolderMember, ServiceMember]
}
export interface ServiceMember {
name: string
type: MemberType.service
code: string
}
export const isFileTree = (arg: any): arg is FileTree =>
arg &&
arg.members &&
Array.isArray(arg.members) &&
arg.members.filter(
(member: FolderMember | ServiceMember) =>
!isFolderMember(member) && !isServiceMember(member)
).length === 0
const isFolderMember = (arg: any): arg is FolderMember =>
arg &&
typeof arg.name === 'string' &&
arg.type === MemberType.folder &&
arg.members &&
Array.isArray(arg.members) &&
arg.members.filter(
(member: FolderMember | ServiceMember) =>
!isFolderMember(member) && !isServiceMember(member)
).length === 0
const isServiceMember = (arg: any): arg is ServiceMember =>
arg &&
typeof arg.name === 'string' &&
arg.type === MemberType.service &&
arg.code &&
typeof arg.code === 'string'

View File

@@ -12,5 +12,3 @@ export * from './Session'
export * from './UploadFile' export * from './UploadFile'
export * from './PollOptions' export * from './PollOptions'
export * from './WriteStream' export * from './WriteStream'
export * from './FileTree'
export * from './ExecuteScript'

View File

@@ -6,8 +6,6 @@ import { JsonParseArrayError, InvalidJsonError } from '../types/errors'
*/ */
export const getValidJson = (str: string | object) => { export const getValidJson = (str: string | object) => {
try { try {
if (str === null || str === undefined) throw new InvalidJsonError()
if (Array.isArray(str)) throw new JsonParseArrayError() if (Array.isArray(str)) throw new JsonParseArrayError()
if (typeof str === 'object') return str if (typeof str === 'object') return str

View File

@@ -5,11 +5,6 @@ enum domIDs {
} }
const cssPrefix = 'sasjs-adapter' const cssPrefix = 'sasjs-adapter'
const classes = {
popUp: `${cssPrefix}popUp`,
popUpBG: `${cssPrefix}popUpBG`
}
export const openLoginPrompt = (): Promise<boolean> => { export const openLoginPrompt = (): Promise<boolean> => {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
const style = document.createElement('style') const style = document.createElement('style')
@@ -18,11 +13,11 @@ export const openLoginPrompt = (): Promise<boolean> => {
const loginPromptBG = document.createElement('div') const loginPromptBG = document.createElement('div')
loginPromptBG.id = domIDs.overlay loginPromptBG.id = domIDs.overlay
loginPromptBG.classList.add(classes.popUpBG) loginPromptBG.classList.add(`${cssPrefix}popUpBG`)
const loginPrompt = document.createElement('div') const loginPrompt = document.createElement('div')
loginPrompt.id = domIDs.dialog loginPrompt.id = domIDs.dialog
loginPrompt.classList.add(classes.popUp) loginPrompt.classList.add(`${cssPrefix}popUp`)
const title = document.createElement('h1') const title = document.createElement('h1')
title.innerText = 'Session Expired!' title.innerText = 'Session Expired!'
@@ -69,11 +64,11 @@ const closeLoginPrompt = () => {
} }
const cssContent = ` const cssContent = `
.${classes.popUpBG} , .${cssPrefix}popUpBG ,
.${classes.popUp} { .${cssPrefix}popUp {
z-index: 10000; z-index: 10000;
} }
.${classes.popUp} { .${cssPrefix}popUp {
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -96,7 +91,7 @@ const cssContent = `
max-height: 300px; max-height: 300px;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
.${classes.popUp} > h1 { .${cssPrefix}popUp > h1 {
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -111,7 +106,7 @@ const cssContent = `
border-width: 5px; border-width: 5px;
border-color: black; border-color: black;
} }
.${classes.popUp} > div { .${cssPrefix}popUp > div {
width: 100%; width: 100%;
height: calc(100% -108px); height: calc(100% -108px);
margin: 0; margin: 0;
@@ -126,7 +121,7 @@ const cssContent = `
border-style: none none solid none; border-style: none none solid none;
overflow: auto; overflow: auto;
} }
.${classes.popUp} > div > span { .${cssPrefix}popUp > div > span {
display: table-cell; display: table-cell;
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
@@ -138,13 +133,13 @@ const cssContent = `
vertical-align: middle; vertical-align: middle;
border-style: none; border-style: none;
} }
.${classes.popUp} .cancel { .${cssPrefix}popUp .cancel {
float: left; float: left;
} }
.${classes.popUp} .confirm { .${cssPrefix}popUp .confirm {
float: right; float: right;
} }
.${classes.popUp} > button { .${cssPrefix}popUp > button {
box-sizing: border-box; box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
@@ -158,10 +153,10 @@ const cssContent = `
height: 50px; height: 50px;
background: rgba(1, 1, 1, 0.2); background: rgba(1, 1, 1, 0.2);
} }
.${classes.popUp} > button:hover { .${cssPrefix}popUp > button:hover {
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
} }
.${classes.popUpBG} { .${cssPrefix}popUpBG {
display: block; display: block;
position: fixed; position: fixed;
top: 0; top: 0;

View File

@@ -25,6 +25,6 @@ export const parseSasViyaDebugResponse = async (
} }
return requestClient return requestClient
.get(serverUrl + jsonUrl, undefined, 'text/plain') .get(serverUrl + jsonUrl, undefined)
.then((res: any) => getValidJson(res.result)) .then((res: any) => getValidJson(res.result))
} }