From 67436f4ff9bb4d77d5f897f47a3e3d472981f275 Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Tue, 2 Jul 2024 15:54:59 +0200 Subject: [PATCH] fix: refactored adapter request wrapper function to return job log as well --- .../sections/manual/manual.component.ts | 7 +- .../sasjs-configurator.component.ts | 15 +- client/src/app/editor/editor.component.ts | 30 +-- client/src/app/group/group.component.ts | 27 +-- .../src/app/licensing/licensing.component.ts | 5 +- client/src/app/lineage/lineage.component.ts | 57 +++--- client/src/app/metadata/metadata.component.ts | 43 ++--- client/src/app/models/UploadFile.ts | 4 + .../RequestWrapperOptions.ts | 0 .../request-wrapper/RequestWrapperResponse.ts | 4 + .../multi-dataset.component.html | 171 ++++++++++++------ .../multi-dataset.component.scss | 4 + .../multi-dataset/multi-dataset.component.ts | 162 ++++++++++------- client/src/app/role/role.component.ts | 43 ++--- client/src/app/services/app.service.ts | 47 ++--- client/src/app/services/sas-store.service.ts | 12 +- client/src/app/services/sas.service.ts | 77 ++++++-- .../app/shared/sidebar/sidebar.component.scss | 1 - .../src/app/shared/terms/terms.component.ts | 5 +- client/src/app/stage/stage.component.ts | 7 +- client/src/app/system/system.component.ts | 13 +- client/src/app/user/user.component.ts | 55 +++--- client/src/app/viewer/viewer.component.ts | 9 +- client/src/app/xlmap/xlmap.component.ts | 13 +- 24 files changed, 489 insertions(+), 322 deletions(-) create mode 100644 client/src/app/models/UploadFile.ts rename client/src/app/models/{ => request-wrapper}/RequestWrapperOptions.ts (100%) create mode 100644 client/src/app/models/request-wrapper/RequestWrapperResponse.ts diff --git a/client/src/app/deploy/sections/manual/manual.component.ts b/client/src/app/deploy/sections/manual/manual.component.ts index 44aa5ea..aa614f0 100644 --- a/client/src/app/deploy/sections/manual/manual.component.ts +++ b/client/src/app/deploy/sections/manual/manual.component.ts @@ -1,6 +1,7 @@ import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core' import SASjs, { SASjsConfig } from '@sasjs/adapter' import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings' +import { RequestWrapperResponse } from 'src/app/models/request-wrapper/RequestWrapperResponse' import { DeployService } from 'src/app/services/deploy.service' import { EventService } from 'src/app/services/event.service' import { LoggerService } from 'src/app/services/logger.service' @@ -303,10 +304,10 @@ export class ManualComponent implements OnInit { this.sasService .request('public/startupservice', null) - .then((res: any) => { - this.loggerService.log(res) + .then((res: RequestWrapperResponse) => { + this.loggerService.log(res.adapterResponse) - if (res.saslibs) { + if (res.adapterResponse.saslibs) { this.validationState = 'success' } else { this.validationState = 'error' diff --git a/client/src/app/deploy/sections/sasjs-configurator/sasjs-configurator.component.ts b/client/src/app/deploy/sections/sasjs-configurator/sasjs-configurator.component.ts index ad0e2dc..38144f0 100644 --- a/client/src/app/deploy/sections/sasjs-configurator/sasjs-configurator.component.ts +++ b/client/src/app/deploy/sections/sasjs-configurator/sasjs-configurator.component.ts @@ -3,6 +3,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' import SASjs, { SASjsConfig } from '@sasjs/adapter' import { ServerType } from '@sasjs/utils/types/serverType' import { DcAdapterSettings } from 'src/app/models/DcAdapterSettings' +import { RequestWrapperResponse } from 'src/app/models/request-wrapper/RequestWrapperResponse' import { SASGroup } from 'src/app/models/sas/public-getgroups.model' import { SASjsApiServerInfo } from 'src/app/models/sasjs-api/SASjsApiServerInfo.model' import { SasService } from 'src/app/services/sas.service' @@ -68,11 +69,11 @@ export class SasjsConfiguratorComponent implements OnInit { this.loading = true this.sasService.request('usernav/usergroupsbymember', null).then( - (res: any) => { - this.METAPERSON = res.MF_GETUSER - this.SYSUSERID = res.SYSUSERID - this.SYSHOSTNAME = res.SYSHOSTNAME - this.SYSVLONG = res.SYSVLONG + (res: RequestWrapperResponse) => { + this.METAPERSON = res.adapterResponse.MF_GETUSER + this.SYSUSERID = res.adapterResponse.SYSUSERID + this.SYSHOSTNAME = res.adapterResponse.SYSHOSTNAME + this.SYSVLONG = res.adapterResponse.SYSVLONG /* We would like to present a default DCPATH (deployment path) to the @@ -88,12 +89,12 @@ export class SasjsConfiguratorComponent implements OnInit { */ this.dcDirectory = this.tmpDirectories[ - ['L', 'H', 'A', 'S'].includes(res.SYSSCPL.substring(0, 1)) + ['L', 'H', 'A', 'S'].includes(res.adapterResponse.SYSSCPL.substring(0, 1)) ? 'linux' : 'windows' ] - this.dcAdminGroupList = res.groups + this.dcAdminGroupList = res.adapterResponse.groups this.dcAdminGroup = this.dcAdminGroupList[0].GROUPNAME this.loading = false diff --git a/client/src/app/editor/editor.component.ts b/client/src/app/editor/editor.component.ts index 75fe59f..7f145f4 100644 --- a/client/src/app/editor/editor.component.ts +++ b/client/src/app/editor/editor.component.ts @@ -61,6 +61,8 @@ import { ParseResult, SpreadsheetService } from '../services/spreadsheet.service' +import { UploadFileResponse } from '../models/UploadFile' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-editor', @@ -571,20 +573,20 @@ export class EditorComponent implements OnInit, AfterViewInit { this.sasService .uploadFile(this.uploadUrl, filesToUpload, { table: this.libds }) .then( - (res: any) => { - if (typeof res.sasjsAbort === 'undefined') { - if (typeof res.sasparams === 'undefined') { + (res: UploadFileResponse) => { + if (typeof res.adapterResponse.sasjsAbort === 'undefined') { + if (typeof res.adapterResponse.sasparams === 'undefined') { return } else { this.uploadLoading = false - let params = res.sasparams[0] + let params = res.adapterResponse.sasparams[0] this.successEnable = true this.tableId = params.DSID this.router.navigateByUrl('/stage/' + this.tableId) } } else { // handle succesfull response - const abortRes = res + const abortRes = res.adapterResponse const abortMsg = abortRes.sasjsAbort[0].MSG const macMsg = abortRes.sasjsAbort[0].MAC @@ -609,7 +611,7 @@ export class EditorComponent implements OnInit, AfterViewInit { this.fileUploadInputCompList.first.nativeElement.value = '' } this.uploader.queue = [] - this.eventService.catchResponseError('file upload', err) + this.eventService.catchResponseError('file upload', err.adapterResponse) } ) } @@ -1561,9 +1563,9 @@ export class EditorComponent implements OnInit, AfterViewInit { 'editors/stagedata', this.$dataFormats ) - .then((res: any) => { - if (typeof res.sasparams !== 'undefined') { - this.router.navigateByUrl('/stage/' + res.sasparams[0].DSID) + .then((res: RequestWrapperResponse) => { + if (typeof res.adapterResponse.sasparams !== 'undefined') { + this.router.navigateByUrl('/stage/' + res.adapterResponse.sasparams[0].DSID) return true } @@ -1591,7 +1593,7 @@ export class EditorComponent implements OnInit, AfterViewInit { this.disableSubmit = true this.submit = false - let errorText = typeof err === 'string' ? err : JSON.stringify(err) + let errorText = typeof err.adapterRespnse === 'string' ? err.adapterRespnse : JSON.stringify(err.adapterRespnse) this.eventService.showAbortModal( 'editors/stagedata', @@ -1983,8 +1985,8 @@ export class EditorComponent implements OnInit, AfterViewInit { suppressSuccessAbortModal: true, suppressErrorAbortModal: true }) - .then((res: any) => { - const colSource = res.dynamic_values.map( + .then((res: RequestWrapperResponse) => { + const colSource = res.adapterResponse.dynamic_values.map( (el: any) => el[this.cellValidationFields.RAW_VALUE] ) @@ -1998,8 +2000,8 @@ export class EditorComponent implements OnInit, AfterViewInit { ...this.cellValidationSource[validationSourceIndex], row: row, col: column, - values: res.dynamic_values, - extended_values: res.dynamic_extended_values + values: res.adapterResponse.dynamic_values, + extended_values: res.adapterResponse.dynamic_extended_values } } diff --git a/client/src/app/group/group.component.ts b/client/src/app/group/group.component.ts index 6c5be2f..0539c86 100644 --- a/client/src/app/group/group.component.ts +++ b/client/src/app/group/group.component.ts @@ -6,6 +6,7 @@ import { ServerType } from '@sasjs/utils/types/serverType' import { HelperService } from '../services/helper.service' import { SasService } from '../services/sas.service' import { globals } from '../_globals' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-group', @@ -82,10 +83,10 @@ export class GroupComponent implements OnInit { globals.usernav.groupList = groups }) } else { - this.sasService.request('public/getgroups', null).then((res: any) => { + this.sasService.request('public/getgroups', null).then((res: RequestWrapperResponse) => { this.loading = false - this.groups = res.groups - globals.usernav.groupList = res.groups + this.groups = res.adapterResponse.groups + globals.usernav.groupList = res.adapterResponse.groups }) } } else { @@ -128,14 +129,14 @@ export class GroupComponent implements OnInit { let data = { iwant: [{ groupid: this.paramURI }] } this.sasService .request('usernav/usermembersbygroup', data) - .then((res: any) => { - this.groupMembers = res.sasmembers - this.groupMemberCount = res.sasmembers.length - if (res.sasmembers[0] !== undefined) { + .then((res: RequestWrapperResponse) => { + this.groupMembers = res.adapterResponse.sasmembers + this.groupMemberCount = res.adapterResponse.sasmembers.length + if (res.adapterResponse.sasmembers[0] !== undefined) { this.loading = false - this.groupUri = res.sasmembers[0].URIMEM || this.paramURI - this.groupName = res.sasmembers[0].GROUPNAME - this.groupDesc = res.sasmembers[0].GROUPDESC + this.groupUri = res.adapterResponse.sasmembers[0].URIMEM || this.paramURI + this.groupName = res.adapterResponse.sasmembers[0].GROUPNAME + this.groupDesc = res.adapterResponse.sasmembers[0].GROUPDESC if (!this.groupName) { this.groupName = this.paramURI @@ -202,13 +203,13 @@ export class GroupComponent implements OnInit { this.sasService .request('usernav/usermembersbygroup', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false this.groupUri = group.GROUPURI this.groupName = group.GROUPNAME this.groupDesc = group.GROUPDESC - this.groupMembers = res.sasmembers - this.groupMemberCount = res.sasmembers.length + this.groupMembers = res.adapterResponse.sasmembers + this.groupMemberCount = res.adapterResponse.sasmembers.length }) } } diff --git a/client/src/app/licensing/licensing.component.ts b/client/src/app/licensing/licensing.component.ts index 61e7ad7..01bb57a 100644 --- a/client/src/app/licensing/licensing.component.ts +++ b/client/src/app/licensing/licensing.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' import { AppService, LicenceService, SasService } from '../services' import { LicenseKeyData } from '../models/LicenseKeyData' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' enum LicenseActions { key = 'key', @@ -116,8 +117,8 @@ export class LicensingComponent implements OnInit { this.sasService .request('admin/registerkey', table) - .then((res: any) => { - if (res.return && res.return[0] && res.return[0].MSG === 'SUCCESS') { + .then((res: RequestWrapperResponse) => { + if (res.adapterResponse.return && res.adapterResponse.return[0] && res.adapterResponse.return[0].MSG === 'SUCCESS') { location.replace(location.href.split('#')[0]) } }) diff --git a/client/src/app/lineage/lineage.component.ts b/client/src/app/lineage/lineage.component.ts index ee1a740..32bc431 100644 --- a/client/src/app/lineage/lineage.component.ts +++ b/client/src/app/lineage/lineage.component.ts @@ -9,6 +9,7 @@ import { SasService } from '../services/sas.service' import * as saveSvg from 'save-svg-as-png' import { LoggerService } from '../services/logger.service' import { LicenceService } from '../services/licence.service' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' const moment = require('moment') @Component({ @@ -115,8 +116,8 @@ export class LineageComponent { await this.sasService .request('lineage/getmetacols', libTable) - .then((res: any) => { - this.columnsList = res.metacols + .then((res: RequestWrapperResponse) => { + this.columnsList = res.adapterResponse.metacols if (this.columnsList && this.columnsList.length > 0) { // this.column = this.columnsList[0]['COLURI'] @@ -174,8 +175,8 @@ export class LineageComponent { let libTable = { SASControlTable: [{ liburi: $event }] } await this.sasService .request('lineage/getmetatables', libTable) - .then((res: any) => { - this.tablesList = res.metatables + .then((res: RequestWrapperResponse) => { + this.tablesList = res.adapterResponse.metatables if (this.tablesList && this.tablesList.length > 0) { library['tables'] = this.tablesList @@ -295,8 +296,8 @@ export class LineageComponent { } else { await this.sasService .request('public/viewlibs', null) - .then((res: any) => { - this.libraryList = res.saslibs + .then((res: RequestWrapperResponse) => { + this.libraryList = res.adapterResponse.saslibs this.helperService.displayLibraries(this.libraryList) if (this.libraryList) { @@ -402,8 +403,8 @@ export class LineageComponent { return new Promise((resolve, reject) => { this.sasService .request('lineage/fetchtablelineage', libTable) - .then(async (res: any) => { - if (res.flatdata.length > 0) { + .then(async (res: RequestWrapperResponse) => { + if (res.adapterResponse.flatdata.length > 0) { if (this.licenceService.checkLineageLimit()) { this.eventService.showInfoModal( 'Notice', @@ -421,20 +422,20 @@ export class LineageComponent { } this.lineageTableName = - res.info[0].LIBREF + '.' + res.info[0].TABLENAME + res.adapterResponse.info[0].LIBREF + '.' + res.adapterResponse.info[0].TABLENAME - let dotArray = res.finalfinal + let dotArray = res.adapterResponse.finalfinal let vizTmp: string = '' for (let i = 0; i < dotArray.length; i++) { vizTmp += unescape(dotArray[i].LINE) + '\n' } - this.flatdata = res.flatdata + this.flatdata = res.adapterResponse.flatdata if (this.libraryList) { let libraryToSelect = this.libraryList.find((library: any) => - res.info[0].LIBURI.toUpperCase().includes( + res.adapterResponse.info[0].LIBURI.toUpperCase().includes( library.LIBRARYID.toUpperCase() ) ) @@ -450,7 +451,7 @@ export class LineageComponent { if (libraryToSelect['tables']) { tableToSelect = libraryToSelect['tables'].find((table: any) => table.TABLEURI.toUpperCase().includes( - res.info[0].TABLEID.toUpperCase() + res.adapterResponse.info[0].TABLEID.toUpperCase() ) ) @@ -495,10 +496,10 @@ export class LineageComponent { .replace(/\sds:/g, '\nds:') .replace(/\s\n/g, '\n') - this.idlookup = res.idlookup + this.idlookup = res.adapterResponse.idlookup - if (res.finalfinal.length > this.largeDotFileLimit) { - this.largeDotFileLines = res.finalfinal.length + if (res.adapterResponse.finalfinal.length > this.largeDotFileLimit) { + this.largeDotFileLines = res.adapterResponse.finalfinal.length } else { this.buildGraph() } @@ -619,8 +620,8 @@ export class LineageComponent { return new Promise((resolve, reject) => { this.sasService .request('lineage/fetchcollineage', libTable) - .then(async (res: any) => { - if (res.flatdata.length > 0) { + .then(async (res: RequestWrapperResponse) => { + if (res.adapterResponse.flatdata.length > 0) { if (this.licenceService.checkLineageLimit()) { this.eventService.showInfoModal( 'Notice', @@ -631,18 +632,18 @@ export class LineageComponent { } } - if (typeof res === 'string') { + if (typeof res.adapterResponse === 'string') { this.vizInput = 'digraph G {SAS Error}' this.buildGraph() return } - this.lineageTableName = res.info[0].LIBREF + '.' + res.info[0].TABNAME - this.lineageColumnName = res.info[0].COLNAME + this.lineageTableName = res.adapterResponse.info[0].LIBREF + '.' + res.adapterResponse.info[0].TABNAME + this.lineageColumnName = res.adapterResponse.info[0].COLNAME - this.idlookup = res.idlookup + this.idlookup = res.adapterResponse.idlookup - let dotArray = res.fromsas + let dotArray = res.adapterResponse.fromsas let vizTmp: string = '' for (let i = 0; i < dotArray.length; i++) { vizTmp += unescape(dotArray[i].STRING) + '\n' @@ -653,11 +654,11 @@ export class LineageComponent { .replace(/\sds:/g, '\nds:') .replace(/\s\n/g, '\n') - this.flatdata = res.flatdata + this.flatdata = res.adapterResponse.flatdata if (this.libraryList) { let libraryToSelect = this.libraryList.find((library: any) => - res.info[0]?.LIBURI?.toUpperCase()?.includes( + res.adapterResponse.info[0]?.LIBURI?.toUpperCase()?.includes( library?.LIBRARYID?.toUpperCase() ) ) @@ -672,7 +673,7 @@ export class LineageComponent { if (libraryToSelect['tables']) { tableToSelect = libraryToSelect['tables'].find( - (table: any) => table.TABLEURI === res.info[0].TABURI + (table: any) => table.TABLEURI === res.adapterResponse.info[0].TABURI ) if (tableToSelect) { @@ -714,8 +715,8 @@ export class LineageComponent { } } - if (res.fromsas.length > this.largeDotFileLimit) { - this.largeDotFileLines = res.fromsas.length + if (res.adapterResponse.fromsas.length > this.largeDotFileLimit) { + this.largeDotFileLines = res.adapterResponse.fromsas.length } else { this.buildGraph() } diff --git a/client/src/app/metadata/metadata.component.ts b/client/src/app/metadata/metadata.component.ts index 0964de9..301df93 100644 --- a/client/src/app/metadata/metadata.component.ts +++ b/client/src/app/metadata/metadata.component.ts @@ -9,6 +9,7 @@ import { SasService } from '../services/sas.service' import { globals } from '../_globals' import { Injectable } from '@angular/core' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' interface MetaData { NAME: any @@ -109,26 +110,26 @@ export class MetadataComponent implements OnInit { this.metatypesLoading = false this.metaDataSearch = globals.metadata.metaDataSearch } else { - this.sasService.request('metanav/metatypes', null).then((res: any) => { - this.metaDataList = res.types + this.sasService.request('metanav/metatypes', null).then((res: RequestWrapperResponse) => { + this.metaDataList = res.adapterResponse.types globals.metadata.metaDataList = this.metaDataList this.loading = false this.metatypesLoading = false }) - this.sasService.request('metanav/metarepos', null).then((res: any) => { + this.sasService.request('metanav/metarepos', null).then((res: RequestWrapperResponse) => { let foundation = false this.repositories = [] - for (let index = 0; index < res.outrepos.length; index++) { - this.repositories.push(res.outrepos[index].NAME) - if (res.outrepos[index].NAME === 'Foundation') { + for (let index = 0; index < res.adapterResponse.outrepos.length; index++) { + this.repositories.push(res.adapterResponse.outrepos[index].NAME) + if (res.adapterResponse.outrepos[index].NAME === 'Foundation') { foundation = true } } if (foundation) { this.repository = 'Foundation' } else { - this.repository = res.outrepos[0].NAME + this.repository = res.adapterResponse.outrepos[0].NAME } globals.metadata.metaRepositories = this.repositories globals.metadata.selectedRepository = this.repository @@ -183,8 +184,8 @@ export class MetadataComponent implements OnInit { const data: any = { SASControlTable: [{ metatype: $event, repo: this.repository }] } - this.sasService.request('metanav/metaobjects', data).then((res: any) => { - this.metaObjectList = res.objects + this.sasService.request('metanav/metaobjects', data).then((res: RequestWrapperResponse) => { + this.metaObjectList = res.adapterResponse.objects this.getMetaObjectAttributes(this.metaObjectSize) this.loading = false this.assoTypeSelected = $event @@ -197,12 +198,12 @@ export class MetadataComponent implements OnInit { let data: any = { SASControlTable: [{ objecturi: $event }] } - this.sasService.request('metanav/metadetails', data).then((res: any) => { - this.metaObjectAssociations = res.associations - this.root$ = of(this.getAssosiationsCount(res.associations)) + this.sasService.request('metanav/metadetails', data).then((res: RequestWrapperResponse) => { + this.metaObjectAssociations = res.adapterResponse.associations + this.root$ = of(this.getAssosiationsCount(res.adapterResponse.associations)) this.showAcc = true this.showTable = true - let metaObjectName = res.attributes.find( + let metaObjectName = res.adapterResponse.attributes.find( (x: any) => x.NAME === 'Name' ).VALUE this.assoObjectSelected = metaObjectName @@ -221,7 +222,7 @@ export class MetadataComponent implements OnInit { url + '/object/' + $event.slice(1 + $event.indexOf('\\')) ) } - this.metaObjectAttributes = res.attributes + this.metaObjectAttributes = res.adapterResponse.attributes }) } @@ -229,8 +230,8 @@ export class MetadataComponent implements OnInit { let data: any = { SASControlTable: [{ objecturi: $event }] } - this.sasService.request('metanav/metadetails', data).then((res: any) => { - this.metaObjectAttributes = res.attributes + this.sasService.request('metanav/metadetails', data).then((res: RequestWrapperResponse) => { + this.metaObjectAttributes = res.adapterResponse.attributes this.showTable = true }) } @@ -244,7 +245,7 @@ export class MetadataComponent implements OnInit { details: [] }) } - let assocObj = assosiationsHash.get(assosiation.ASSOC) + let assocObj: any = assosiationsHash.get(assosiation.ASSOC) assocObj.count++ assocObj.details.push({ ASSOCURI: assosiation.ASSOCURI, @@ -254,7 +255,7 @@ export class MetadataComponent implements OnInit { }) } let assocGrouped: Array = [] - assosiationsHash.forEach(function (val, key) { + assosiationsHash.forEach(function (val: any, key) { assocGrouped.push({ ASSOC: key, count: val.count, @@ -294,9 +295,9 @@ export class MetadataComponent implements OnInit { } return this.sasService .request('metanav/metadetails', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.showTable = true - this.metaObjectAttributes = res.attributes + this.metaObjectAttributes = res.adapterResponse.attributes this.assoObjectSelected = asso.NAME let url = this.router.url if (this.objectRoute) { @@ -314,7 +315,7 @@ export class MetadataComponent implements OnInit { asso.ASSOCURI.slice(1 + asso.ASSOCURI.indexOf('\\')) ) } - return this.getAssosiationsCount(res.associations) + return this.getAssosiationsCount(res.adapterResponse.associations) }) } diff --git a/client/src/app/models/UploadFile.ts b/client/src/app/models/UploadFile.ts new file mode 100644 index 0000000..ca746cb --- /dev/null +++ b/client/src/app/models/UploadFile.ts @@ -0,0 +1,4 @@ +export interface UploadFileResponse { + adapterResponse: any, + log?: string +} \ No newline at end of file diff --git a/client/src/app/models/RequestWrapperOptions.ts b/client/src/app/models/request-wrapper/RequestWrapperOptions.ts similarity index 100% rename from client/src/app/models/RequestWrapperOptions.ts rename to client/src/app/models/request-wrapper/RequestWrapperOptions.ts diff --git a/client/src/app/models/request-wrapper/RequestWrapperResponse.ts b/client/src/app/models/request-wrapper/RequestWrapperResponse.ts new file mode 100644 index 0000000..c653177 --- /dev/null +++ b/client/src/app/models/request-wrapper/RequestWrapperResponse.ts @@ -0,0 +1,4 @@ +export interface RequestWrapperResponse { + adapterResponse: responseType + log?: string +} \ No newline at end of file diff --git a/client/src/app/multi-dataset/multi-dataset.component.html b/client/src/app/multi-dataset/multi-dataset.component.html index ed4efa9..c23f29f 100644 --- a/client/src/app/multi-dataset/multi-dataset.component.html +++ b/client/src/app/multi-dataset/multi-dataset.component.html @@ -22,8 +22,8 @@ /> - -
+ +
@@ -41,30 +41,60 @@ - +

Submitted tables:

- + + +
+
+ +
+
+ {{ activeParsedDataset.submitResult?.error | json }} +
+
+ +

Found in range: @@ -197,7 +277,12 @@ - No data found + No data found + + + Searching for the data... + +

@@ -262,9 +347,9 @@ - +

- +
-

- Found in range: - "{{ - activeSubmittedDataset.parseResult.rangeSheetRes?.sheetName - }}"!{{ - activeSubmittedDataset.parseResult.rangeSheetRes?.rangeAddress - }} -

Matched with dataset: {{ activeSubmittedDataset.libds }}{{ activeSubmittedCsvDataset.libds }}

Status: - SUCCESS - ERROR

Error details: @@ -331,18 +402,10 @@

-
-
+
- {{ activeSubmittedDataset.error | json }} + {{ activeSubmittedCsvDataset.error | json }}
diff --git a/client/src/app/multi-dataset/multi-dataset.component.scss b/client/src/app/multi-dataset/multi-dataset.component.scss index 97d7fe3..8dbcfc0 100644 --- a/client/src/app/multi-dataset/multi-dataset.component.scss +++ b/client/src/app/multi-dataset/multi-dataset.component.scss @@ -47,4 +47,8 @@ .licence-limit-notice { color: var(--cds-alias-status-warning-dark); +} + +.submission-results { + border-bottom: 1px solid #d3d3d3; } \ No newline at end of file diff --git a/client/src/app/multi-dataset/multi-dataset.component.ts b/client/src/app/multi-dataset/multi-dataset.component.ts index d276f81..9e3cf58 100644 --- a/client/src/app/multi-dataset/multi-dataset.component.ts +++ b/client/src/app/multi-dataset/multi-dataset.component.ts @@ -29,6 +29,8 @@ import { CellChange, ChangeSource } from 'handsontable/common' import { baseAfterGetColHeader } from '../shared/utils/hot.utils' import { ColumnSettings } from 'handsontable/settings' import { UploadFile } from '@sasjs/adapter' +import { UploadFileResponse } from '../models/UploadFile' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-multi-dataset', @@ -48,15 +50,19 @@ export class MultiDatasetComponent implements OnInit { public csvFiles: UploadFile[] = [] public csvSubmitting: boolean = false - public selectedFile: File | null = null + public autoDetectingColumns: boolean = false + + public selectedFile: SelectedFile | null = null public parsedDatasets: ParsedDataset[] = [] - public submittedDatasets: SubmittedDatasetResult[] = [] + public submittedCsvDatasets: SubmittedCsvDatasetResult[] = [] public datasetsLoading: boolean = false public uploadLoading: boolean = false public submitLoading: boolean = false public matchedDatasets: string[] = [] + public sheetNames: string[] = [] + public userInputDatasets: string = '' public libsAndTables: { @@ -194,6 +200,8 @@ export class MultiDatasetComponent implements OnInit { // For EXCEL if multiple files, we only take one (the first one) this.selectedFile = event.target.files[0] + if (this.selectedFile) this.selectedFile.sizeMB = this.spreadsheetService.bytesToMB(this.selectedFile.size) + this.initUserInputHot() this.onAutoDetectColumns() } else if (matchedExtension === 'csv') { @@ -246,7 +254,7 @@ export class MultiDatasetComponent implements OnInit { this.userInputDatasets = '' } - async onUploadFile() { + async onStartParsingFile() { this.uploadLoading = true const datasetFetchingPromises: Promise< @@ -271,18 +279,27 @@ export class MultiDatasetComponent implements OnInit { const datasetObjects = this.buildDatasetsObjects(datasets) - for (let datasetObject of datasetObjects) { + datasetObjects.forEach((datasetObject) => { + this.parsedDatasets.push({ + libds: datasetObject.libds, + includeInSubmission: true, + datasetInfo: datasetObject, + parsingTable: true + }) + }) + + for (let parsedDataset of this.parsedDatasets) { this.spreadsheetService .parseExcelFile({ file: this.selectedFile!, - dcValidator: datasetObject.dcValidator!, - headerPks: datasetObject.headerPks, - headerArray: datasetObject.headerArray, + dcValidator: parsedDataset.datasetInfo.dcValidator!, + headerPks: parsedDataset.datasetInfo.headerPks, + headerArray: parsedDataset.datasetInfo.headerArray, headerShow: [], - timeHeaders: datasetObject.timeHeaders, - dateHeaders: datasetObject.dateHeaders, - dateTimeHeaders: datasetObject.dateTimeHeaders, - xlRules: datasetObject.xlRules + timeHeaders: parsedDataset.datasetInfo.timeHeaders, + dateHeaders: parsedDataset.datasetInfo.dateHeaders, + dateTimeHeaders: parsedDataset.datasetInfo.dateTimeHeaders, + xlRules: parsedDataset.datasetInfo.xlRules }) .then((parseResult: ParseResult | undefined) => { console.log('parseResult', parseResult) @@ -304,23 +321,17 @@ export class MultiDatasetComponent implements OnInit { datasource.push(itemObject) }) - this.parsedDatasets.push({ - libds: datasetObject.libds, - parseResult: parseResult, - includeInSubmission: true, - datasetInfo: datasetObject, - datasource: datasource - }) + parsedDataset.datasource = datasource + parsedDataset.parseResult = parseResult + parsedDataset.parsingTable = false } }) .catch((error: string) => { console.warn('Parsing excel file error.', error) - this.parsedDatasets.push({ - libds: datasetObject.libds, - includeInSubmission: false, - datasetInfo: datasetObject - }) + parsedDataset.datasource = [] + parsedDataset.includeInSubmission = false + parsedDataset.parsingTable = false }) } }) @@ -507,13 +518,13 @@ export class MultiDatasetComponent implements OnInit { * convention. {@link isValidDatasetFormat} */ async onAutoDetectColumns() { - const sheetNames = await this.parseExcelSheetNames() + this.sheetNames = await this.parseExcelSheetNames() - if (sheetNames) { + if (this.sheetNames) { this.matchedDatasets = [] this.userInputDatasets = '' - sheetNames.forEach((sheetName: string, index: number) => { + this.sheetNames.forEach((sheetName: string, index: number) => { const trimmedSheetname = sheetName.trim() if ( @@ -561,8 +572,8 @@ export class MultiDatasetComponent implements OnInit { this.initHot() } - onSubmittedDatasetClick(submittedDataset: SubmittedDatasetResult) { - this.deselectAllSubmittedDatasets() + onSubmittedCsvDatasetClick(submittedDataset: SubmittedCsvDatasetResult) { + this.deselectAllSubmittedCsvDatasets() submittedDataset.active = true } @@ -571,8 +582,8 @@ export class MultiDatasetComponent implements OnInit { return this.parsedDatasets.find((dataset) => dataset.active) } - public get activeSubmittedDataset(): SubmittedDatasetResult | undefined { - return this.submittedDatasets.find((dataset) => dataset.active) + public get activeSubmittedCsvDataset(): SubmittedCsvDatasetResult | undefined { + return this.submittedCsvDatasets.find((dataset) => dataset.active) } public get notFoundDatasets(): string[] { @@ -606,8 +617,12 @@ export class MultiDatasetComponent implements OnInit { return this.csvFiles.length > 0 } + public get excelsSubmitted(): boolean { + return !!this.parsedDatasets.filter(ds => ds.submitResult).length + } + public downloadFile(response: any) { - const filename = `stagedata-${this.activeSubmittedDataset?.libds}-log` + const filename = `stagedata-${this.activeSubmittedCsvDataset?.libds}-log` this.helperService.downloadTextFile(filename, JSON.stringify(response)) } @@ -615,7 +630,7 @@ export class MultiDatasetComponent implements OnInit { * Submits attached CSVs which are matched with existing datasets */ async submitCsvFiles() { - let requestsResults: SubmittedDatasetResult[] = [] + let requestsResults: SubmittedCsvDatasetResult[] = [] for (let file of this.csvFiles) { const libds = this.parseDatasetFromCsvName(file.fileName) @@ -626,17 +641,17 @@ export class MultiDatasetComponent implements OnInit { await this.sasService .uploadFile('services/editors/loadfile', [file], { table: libds }) .then( - (res: any) => { - if (typeof res.sasjsAbort !== 'undefined') { - error = res.sasjsAbort + (res: UploadFileResponse) => { + if (typeof res.adapterResponse.sasjsAbort !== 'undefined') { + error = res.adapterResponse.sasjsAbort } else { - success = res + success = res.adapterResponse } }, (err: any) => { console.error('err', err) - error = err + error = err.adapterResponse } ) @@ -647,7 +662,7 @@ export class MultiDatasetComponent implements OnInit { }) } - this.submittedDatasets = requestsResults + this.submittedCsvDatasets = requestsResults } /** @@ -678,7 +693,7 @@ export class MultiDatasetComponent implements OnInit { } /** - * Sends tables to the SAS sequentially + * Sends tables found in an excel to the SAS sequentially * * @param explicitDatasets if empty all datasets will be sent, otherwise only datasets * in the array will be sent. eg. ['lib1.table_1', 'lib1.table_2'] @@ -688,10 +703,6 @@ export class MultiDatasetComponent implements OnInit { this.submitLoading = true - let requestsResults: SubmittedDatasetResult[] = explicitDatasets - ? this.submittedDatasets - : [] - for (let table of this.parsedDatasets) { // Skip the table if no data inside if (!table.parseResult || !table.datasource) continue @@ -733,6 +744,7 @@ export class MultiDatasetComponent implements OnInit { let error let success + let log await this.sasStoreService .updateTable( @@ -741,56 +753,47 @@ export class MultiDatasetComponent implements OnInit { 'SASControlTable', 'editors/stagedata', table.datasetInfo.data.$sasdata, - true + true, + { + debug: true + } ) - .then((res: EditorsStageDataSASResponse) => { - success = res + .then((res: RequestWrapperResponse) => { + success = res.adapterResponse + log = res.log }) .catch((err: any) => { console.error('err', err) - error = err + error = err.adapterResponse + log = err.log }) const requestResult = { success, error, + log, parseResult: table.parseResult, libds: table.libds } - // If explicit datasets are set don't just push to th array - // instead replace if result already exist from before (this might be re-submit) - if (explicitDatasets) { - const existingResultIndex = requestsResults.findIndex( - (result) => result.libds === table.libds - ) - - if (existingResultIndex > -1) { - requestsResults[existingResultIndex] = requestResult - } else { - requestsResults.push(requestResult) - } - } else { - requestsResults.push(requestResult) - } + table.submitResult = requestResult } } - - this.submittedDatasets = requestsResults this.showSubmitReasonModal = false this.submitLoading = false this.deselectAllParsedDatasets() } - async reSubmitTable(activeSubmittedDataset: SubmittedDatasetResult) { + async reSubmitTable(activeSubmittedDataset: ParsedDataset) { // Submit only particular table await this.submitTables([activeSubmittedDataset.libds]) // Activate new resubmitted table - const newSubmittedDataset = this.submittedDatasets.find( + const newSubmittedDataset = this.parsedDatasets.find( (sd) => sd.libds === activeSubmittedDataset.libds ) + if (newSubmittedDataset) newSubmittedDataset.active = true } @@ -815,6 +818,12 @@ export class MultiDatasetComponent implements OnInit { .map((row) => (row ? `${row[0]}.${row[1]}` : '')) } + /** + * Read the file minimally just to get the sheet names, not reading full file + * to help boost the performance + * + * @returns sheet names in string array + */ private parseExcelSheetNames(): Promise { return new Promise((resolve, reject) => { const reader = new FileReader() @@ -832,6 +841,8 @@ export class MultiDatasetComponent implements OnInit { const data = event.target.result const workbook = XLSX.read(data, { + // Load file minimally to parse sheets + bookSheets: true, type: 'binary' }) @@ -977,8 +988,8 @@ export class MultiDatasetComponent implements OnInit { } } - private deselectAllSubmittedDatasets() { - for (let submittedDataset of this.submittedDatasets) { + private deselectAllSubmittedCsvDatasets() { + for (let submittedDataset of this.submittedCsvDatasets) { submittedDataset.active = false } } @@ -1001,17 +1012,28 @@ export interface DatasetsObject extends EditorsGetDataServiceResponse { export interface ParsedDataset { libds: string parseResult?: ParseResult - datasetInfo: DatasetsObject + datasetInfo: DatasetsObject, + submitResult?: SubmittedDatasetResult, datasource?: any[] includeInSubmission: boolean status?: 'success' | 'error' active?: boolean + parsingTable?: boolean } export interface SubmittedDatasetResult { + success: EditorsStageDataSASResponse | undefined + error: any, + log?: string +} + +export interface SubmittedCsvDatasetResult { libds: string success: EditorsStageDataSASResponse | undefined error: any - parseResult?: ParseResult active?: boolean } + +export interface SelectedFile extends File { + sizeMB?: number +} \ No newline at end of file diff --git a/client/src/app/role/role.component.ts b/client/src/app/role/role.component.ts index cb66d56..fdf75d6 100644 --- a/client/src/app/role/role.component.ts +++ b/client/src/app/role/role.component.ts @@ -4,6 +4,7 @@ import { HelperService } from '../services/helper.service' import { Location } from '@angular/common' import { Router, ActivatedRoute } from '@angular/router' import { SasService } from '../services/sas.service' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-role', @@ -47,10 +48,10 @@ export class RoleComponent implements OnInit { } else { if (globals.usernav.roleList === undefined) { this.loading = true - this.sasService.request('usernav/userroles', null).then((res: any) => { + this.sasService.request('usernav/userroles', null).then((res: RequestWrapperResponse) => { this.loading = false - this.roles = res.roles - globals.usernav.roleList = res.roles + this.roles = res.adapterResponse.roles + globals.usernav.roleList = res.adapterResponse.roles if (this.paramPresent) { if (this.roles !== undefined) { let validRole = this.findRole(this.roles, this.paramURI) @@ -59,12 +60,12 @@ export class RoleComponent implements OnInit { let data = { iwant: [{ roleid: this.paramURI }] } this.sasService .request('usernav/usermembersbyrole', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false - this.roleMembers = res.sasmembers - this.roleMembersCount = res.sasmembers.length - this.roleGroups = res.sasgroups - this.roleGroupsCount = res.sasgroups.length + this.roleMembers = res.adapterResponse.sasmembers + this.roleMembersCount = res.adapterResponse.sasmembers.length + this.roleGroups = res.adapterResponse.sasgroups + this.roleGroupsCount = res.adapterResponse.sasgroups.length this.roleUri = validRole.ROLEURI this.roleName = validRole.ROLENAME this.roleDesc = validRole.ROLEDESC @@ -76,9 +77,9 @@ export class RoleComponent implements OnInit { } else { this.roles = globals.usernav.roleList this.roleSearch = globals.usernav.roleSearch - this.sasService.request('usernav/userroles', null).then((res: any) => { - this.roles = res.roles - globals.usernav.roleList = res.roles + this.sasService.request('usernav/userroles', null).then((res: RequestWrapperResponse) => { + this.roles = res.adapterResponse.roles + globals.usernav.roleList = res.adapterResponse.roles if (this.paramPresent) { if (this.roles !== undefined) { @@ -88,12 +89,12 @@ export class RoleComponent implements OnInit { let data = { iwant: [{ roleid: this.paramURI }] } this.sasService .request('usernav/usermembersbyrole', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false - this.roleMembers = res.sasmembers - this.roleMembersCount = res.sasmembers.length - this.roleGroups = res.sasgroups - this.roleGroupsCount = res.sasgroups.length + this.roleMembers = res.adapterResponse.sasmembers + this.roleMembersCount = res.adapterResponse.sasmembers.length + this.roleGroups = res.adapterResponse.sasgroups + this.roleGroupsCount = res.adapterResponse.sasgroups.length this.roleUri = validRole.ROLEURI this.roleName = validRole.ROLENAME this.roleDesc = validRole.ROLEDESC @@ -125,12 +126,12 @@ export class RoleComponent implements OnInit { let data = { iwant: [{ roleid: role.ROLEURI }] } this.sasService .request('usernav/usermembersbyrole', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false - this.roleMembers = res.sasmembers - this.roleMembersCount = res.sasmembers.length - this.roleGroups = res.sasgroups - this.roleGroupsCount = res.sasgroups.length + this.roleMembers = res.adapterResponse.sasmembers + this.roleMembersCount = res.adapterResponse.sasmembers.length + this.roleGroups = res.adapterResponse.sasgroups + this.roleGroupsCount = res.adapterResponse.sasgroups.length this.roleUri = role.ROLEURI this.roleName = role.ROLENAME this.roleDesc = role.ROLEDESC diff --git a/client/src/app/services/app.service.ts b/client/src/app/services/app.service.ts index 9cb8687..1ae9d8e 100644 --- a/client/src/app/services/app.service.ts +++ b/client/src/app/services/app.service.ts @@ -9,6 +9,7 @@ import { EnvironmentInfo } from '../system/models/environment-info.model' import { LicenceService } from './licence.service' import { AppSettingsService } from './app-settings.service' import { AppThemes } from '../models/AppSettings' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Injectable() export class AppService { @@ -81,16 +82,16 @@ export class AppService { await this.sasService .request('public/startupservice', null) - .then(async (res: any) => { - this.syssite.next([res.SYSSITE]) + .then(async (res: RequestWrapperResponse) => { + this.syssite.next([res.adapterResponse.SYSSITE]) let missingProps: string[] = [] - if (!res.globvars || (res.globvars && !res.globvars[0])) + if (!res.adapterResponse.globvars || (res.adapterResponse.globvars && !res.adapterResponse.globvars[0])) missingProps.push('Globvars') - if (!res.sasdatasets) missingProps.push('Sasdatasets') - if (!res.saslibs) missingProps.push('Saslibs') - if (!res.xlmaps) missingProps.push('XLMaps') + if (!res.adapterResponse.sasdatasets) missingProps.push('Sasdatasets') + if (!res.adapterResponse.saslibs) missingProps.push('Saslibs') + if (!res.adapterResponse.xlmaps) missingProps.push('XLMaps') if (missingProps.length > 0) { startupServiceError = true @@ -104,22 +105,22 @@ export class AppService { } this.environmentInfo = { - SYSSITE: res.SYSSITE, - SYSSCPL: res.SYSSCPL, - SYSTCPIPHOSTNAME: res.SYSTCPIPHOSTNAME, - SYSVLONG: res.SYSVLONG, - MEMSIZE: res.MEMSIZE, - SYSPROCESSMODE: res.SYSPROCESSMODE, - SYSHOSTNAME: res.SYSHOSTNAME, - SYSUSERID: res.SYSUSERID, - SYSHOSTINFOLONG: res.SYSHOSTINFOLONG, - SYSENCODING: res.SYSENCODING, - AUTOEXEC: res.AUTOEXEC, - ISADMIN: res.globvars[0].ISADMIN, - DC_ADMIN_GROUP: res.globvars[0].DC_ADMIN_GROUP + SYSSITE: res.adapterResponse.SYSSITE, + SYSSCPL: res.adapterResponse.SYSSCPL, + SYSTCPIPHOSTNAME: res.adapterResponse.SYSTCPIPHOSTNAME, + SYSVLONG: res.adapterResponse.SYSVLONG, + MEMSIZE: res.adapterResponse.MEMSIZE, + SYSPROCESSMODE: res.adapterResponse.SYSPROCESSMODE, + SYSHOSTNAME: res.adapterResponse.SYSHOSTNAME, + SYSUSERID: res.adapterResponse.SYSUSERID, + SYSHOSTINFOLONG: res.adapterResponse.SYSHOSTINFOLONG, + SYSENCODING: res.adapterResponse.SYSENCODING, + AUTOEXEC: res.adapterResponse.AUTOEXEC, + ISADMIN: res.adapterResponse.globvars[0].ISADMIN, + DC_ADMIN_GROUP: res.adapterResponse.globvars[0].DC_ADMIN_GROUP } - let libs = res.sasdatasets + let libs = res.adapterResponse.sasdatasets let libGroup: any = {} let libsAndTables let libraries @@ -153,7 +154,7 @@ export class AppService { globals.editor.libsAndTables = libsAndTables } - globals.xlmaps = res.xlmaps.map((xlmap: any) => ({ + globals.xlmaps = res.adapterResponse.xlmaps.map((xlmap: any) => ({ id: xlmap[0], description: xlmap[1], targetDS: xlmap[2] @@ -162,9 +163,9 @@ export class AppService { globals.editor.libraries = libraries globals.editor.startupSet = true - globals.dcLib = res.globvars[0].DCLIB + globals.dcLib = res.adapterResponse.globvars[0].DCLIB - await this.licenceService.activation(res) + await this.licenceService.activation(res.adapterResponse) }) .catch((err: any) => { startupServiceError = true diff --git a/client/src/app/services/sas-store.service.ts b/client/src/app/services/sas-store.service.ts index 54d314e..b92559a 100644 --- a/client/src/app/services/sas-store.service.ts +++ b/client/src/app/services/sas-store.service.ts @@ -18,6 +18,7 @@ import { isSpecialMissing } from '@sasjs/utils/input/validators' import { Col } from '../shared/dc-validator/models/col.model' import { get } from 'lodash-es' import { EditorsStageDataSASResponse } from '../models/sas/editors-stagedata.model' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Injectable() export class SasStoreService { @@ -58,12 +59,12 @@ export class SasStoreService { ) { const tables: any = {} tables[tableName] = [tableData] - const res: EditorsGetDataSASResponse = await this.sasService.request( + const res: RequestWrapperResponse = await this.sasService.request( program, tables ) const response: EditorsGetDataServiceResponse = { - data: res, + data: res.adapterResponse, libds: libds } return response @@ -84,8 +85,9 @@ export class SasStoreService { tableName: string, program: string, $dataFormats: $DataFormats | null, - suppressErrorSuccessMessages?: boolean - ): Promise { + suppressErrorSuccessMessages?: boolean, + adapterConfig?: any + ): Promise> { // add sp as third argument of createData call let tables: any = { @@ -103,7 +105,7 @@ export class SasStoreService { let res = await this.sasService.request( program, tables, - null, + adapterConfig, { suppressErrorAbortModal: suppressErrorSuccessMessages, suppressSuccessAbortModal: suppressErrorSuccessMessages diff --git a/client/src/app/services/sas.service.ts b/client/src/app/services/sas.service.ts index e6c6950..170a65f 100644 --- a/client/src/app/services/sas.service.ts +++ b/client/src/app/services/sas.service.ts @@ -12,8 +12,10 @@ import { ServerType } from '@sasjs/utils/types/serverType' import { DcAdapterSettings } from '../models/DcAdapterSettings' import { AppStoreService } from './app-store.service' import { LoggerService } from './logger.service' -import { RequestWrapperOptions } from '../models/RequestWrapperOptions' +import { RequestWrapperOptions } from '../models/request-wrapper/RequestWrapperOptions' import { ErrorBody } from '../models/ErrorBody' +import { UploadFileResponse } from '../models/UploadFile' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Injectable({ providedIn: 'root' @@ -95,14 +97,16 @@ export class SasService { * @param config additional parameters to force eg. { debug: false } * @param wrapperOptions used to provide options to the request wrapper function * for example to suppress error or success abort modals after request is finished - * @returns + * @returns adapter response or an error. It will return the `log` as well. + * The log could be potentially be wrong if multiple requests happen because the log this + * function return is the last request in the Adapter Array for the given URL. */ public request( url: string, data: any, config?: any, wrapperOptions?: RequestWrapperOptions - ): Promise { + ): Promise> { url = 'services/' + url if (!wrapperOptions) wrapperOptions = {} @@ -117,9 +121,14 @@ export class SasService { }) .then( (res: any) => { + const sasRequest = this.sasjsAdapter.getSasRequests().find(rq => rq.serviceLink === url) + if (res.login === false) { this.shouldLogin.next(true) - reject(false) + reject({ + adapterResponse: false, + log: sasRequest?.logFile + }) } if (!this.userService.user && res.MF_GETUSER) { @@ -141,7 +150,12 @@ export class SasService { } if (res.status === 404) { - reject({ MESSAGE: res.body || 'SAS Responded with error' }) + reject({ + adapterResponse: { + MESSAGE: res.body || 'SAS Responded with error' + }, + log: sasRequest?.logFile + }) } if (typeof res.sasjsAbort !== 'undefined') { @@ -157,7 +171,12 @@ export class SasService { this.eventService.startupDataLoaded() this.router.navigateByUrl('/deploy') - reject({ error: abortMsg }) + reject({ + adapterResponse: { + error: abortMsg + }, + log: sasRequest?.logFile + }) return } @@ -174,14 +193,24 @@ export class SasService { ) } - reject({ error: abortMsg }) + reject({ + adapterResponse: { + error: abortMsg + }, + log: sasRequest?.logFile + }) } - resolve(res) + resolve({ + adapterResponse: res, + log: sasRequest?.logFile + }) }, (err: { error: ErrorBody | undefined }) => { console.error(err) + const sasRequest = this.sasjsAdapter.getSasRequests().find(rq => rq.serviceLink === url) + if (err.error) { let errorMessage: string | undefined = err.error.message let log: string | undefined @@ -205,10 +234,18 @@ export class SasService { 'Request error' ) } - reject({ error: errorMessage }) + reject({ + adapterResponse: { + error: errorMessage + }, + log: sasRequest?.logFile + }) } - reject(err) + reject({ + adapterResponse: err, + log: sasRequest?.logFile + }) } ) }) @@ -222,8 +259,24 @@ export class SasService { * @param params Aditional parameters eg. { debug: false } * @returns HTTP Response */ - public uploadFile(sasService: string, files: UploadFile[], params: any) { - return this.sasjsAdapter.uploadFile(sasService, files, params) + public uploadFile(sasService: string, files: UploadFile[], params: any): Promise { + return new Promise((resolve, reject) => { + this.sasjsAdapter.uploadFile(sasService, files, params).then(res => { + const sasRequest = this.sasjsAdapter.getSasRequests().find(rq => rq.serviceLink === 'services/editors/loadfile') + + resolve({ + adapterResponse: res, + log: sasRequest?.logFile + }) + }, (err) => { + const sasRequest = this.sasjsAdapter.getSasRequests().find(rq => rq.serviceLink === 'services/editors/loadfile') + + reject({ + response: err, + log: sasRequest?.logFile + }) + }) + }) } public async login(username: string, password: string) { diff --git a/client/src/app/shared/sidebar/sidebar.component.scss b/client/src/app/shared/sidebar/sidebar.component.scss index 381c606..822f421 100644 --- a/client/src/app/shared/sidebar/sidebar.component.scss +++ b/client/src/app/shared/sidebar/sidebar.component.scss @@ -2,7 +2,6 @@ $sidebarWidth: 272px; .clr-vertical-nav .nav-link.active { background-color: transparent; - padding-left: 5px; } clr-vertical-nav { diff --git a/client/src/app/shared/terms/terms.component.ts b/client/src/app/shared/terms/terms.component.ts index d23519d..6393914 100644 --- a/client/src/app/shared/terms/terms.component.ts +++ b/client/src/app/shared/terms/terms.component.ts @@ -8,6 +8,7 @@ import { import { SasService } from '../../services/sas.service' import * as marked from 'marked' import { EULA } from 'src/environments/_eula' +import { RequestWrapperResponse } from 'src/app/models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-terms', @@ -51,8 +52,8 @@ export class TermsComponent implements OnInit, AfterViewInit { this.sasService .request(`public/registeruser`, table) - .then((res: any) => { - if (res.return && res.return[0] && res.return[0].MSG === 'SUCCESS') { + .then((res: RequestWrapperResponse) => { + if (res.adapterResponse.return && res.adapterResponse.return[0] && res.adapterResponse.return[0].MSG === 'SUCCESS') { location.reload() } }) diff --git a/client/src/app/stage/stage.component.ts b/client/src/app/stage/stage.component.ts index 76bfb70..e7b3e15 100644 --- a/client/src/app/stage/stage.component.ts +++ b/client/src/app/stage/stage.component.ts @@ -8,6 +8,7 @@ import { HotTableInterface } from '../models/HotTable.interface' import { LicenceService } from '../services/licence.service' import { globals } from '../_globals' import { EditorsRestoreServiceResponse } from '../models/sas/editors-restore.model' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-stage', @@ -180,10 +181,10 @@ export class StageComponent implements OnInit { this.sasService .request('editors/restore', data) - .then((res: EditorsRestoreServiceResponse) => { - if (res.restore_out) { + .then((res: RequestWrapperResponse) => { + if (res.adapterResponse.restore_out) { this.route.navigate([`/stage`]).then(() => { - this.route.navigate([`/stage/${res.restore_out[0].LOADREF}`]) + this.route.navigate([`/stage/${res.adapterResponse.restore_out[0].LOADREF}`]) }) } }) diff --git a/client/src/app/system/system.component.ts b/client/src/app/system/system.component.ts index 5f2f50d..58dbbb7 100644 --- a/client/src/app/system/system.component.ts +++ b/client/src/app/system/system.component.ts @@ -9,6 +9,7 @@ import { AppInfo } from './models/app-info.model' import { EnvironmentInfo } from './models/environment-info.model' import { AppSettingsService } from '../services/app-settings.service' import { AppSettings } from '../models/AppSettings' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-system', @@ -83,12 +84,12 @@ export class SystemComponent implements OnInit { this.sasService .request('admin/refreshcatalog', null) - .then((res: any) => { - this.response = this.parseResponse(res) + .then((res: RequestWrapperResponse) => { + this.response = this.parseResponse(res.adapterResponse) this.responseModal = true }) .catch((err: any) => { - this.response = this.parseResponse(err) + this.response = this.parseResponse(err.adapterResponse) this.responseModal = true }) .finally(() => { @@ -101,12 +102,12 @@ export class SystemComponent implements OnInit { this.sasService .request('admin/refreshtablelineage', null) - .then((res: any) => { - this.response = this.parseResponse(res) + .then((res: RequestWrapperResponse) => { + this.response = this.parseResponse(res.adapterResponse) this.responseModal = true }) .catch((err: any) => { - this.response = this.parseResponse(err) + this.response = this.parseResponse(err.adapterResponse) this.responseModal = true }) .finally(() => { diff --git a/client/src/app/user/user.component.ts b/client/src/app/user/user.component.ts index bc7ee21..136d142 100644 --- a/client/src/app/user/user.component.ts +++ b/client/src/app/user/user.component.ts @@ -6,6 +6,7 @@ import { Location } from '@angular/common' import { SasService } from '../services/sas.service' import { SASjsConfig } from '@sasjs/adapter' import { ServerType } from '@sasjs/utils/types/serverType' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-user', @@ -89,10 +90,10 @@ export class UserComponent implements OnInit { } else { this.sasService .request('usernav/usermembers', null) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false - this.users = res.users - globals.usernav.userList = res.users + this.users = res.adapterResponse.users + globals.usernav.userList = res.adapterResponse.users }) } } else { @@ -141,18 +142,18 @@ export class UserComponent implements OnInit { this.sasService .request('usernav/usergroupsbymember', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false switch (this.serverType) { case ServerType.Sas9: { - this.userInfo = res.info[0] - this.userEmails = res.emails - this.userEmailsCount = res.emails.length - this.userRoles = res.roles - this.userRolesCount = res.roles.length - this.userLogins = res.logins - this.userLoginsCount = res.logins.length + this.userInfo = res.adapterResponse.info[0] + this.userEmails = res.adapterResponse.emails + this.userEmailsCount = res.adapterResponse.emails.length + this.userRoles = res.adapterResponse.roles + this.userRolesCount = res.adapterResponse.roles.length + this.userLogins = res.adapterResponse.logins + this.userLoginsCount = res.adapterResponse.logins.length break } @@ -162,7 +163,7 @@ export class UserComponent implements OnInit { (userAr) => userAr.URI === uri ) } else { - const group = res.groups[0] + const group = res.adapterResponse.groups[0] this.userInfo = { URI: group.ID, @@ -175,9 +176,9 @@ export class UserComponent implements OnInit { } } - this.userData = res - this.userGroups = res.groups - this.userGroupsCount = res.groups.length + this.userData = res.adapterResponse + this.userGroups = res.adapterResponse.groups + this.userGroupsCount = res.adapterResponse.groups.length }) } } @@ -238,18 +239,18 @@ export class UserComponent implements OnInit { let data = { iwant: [{ uri: user.URI }] } this.sasService .request('usernav/usergroupsbymember', data) - .then((res: any) => { + .then((res: RequestWrapperResponse) => { this.loading = false switch (this.serverType) { case ServerType.Sas9: { - this.userInfo = res.info[0] - this.userEmails = res.emails - this.userEmailsCount = res.emails.length - this.userRoles = res.roles - this.userRolesCount = res.roles.length - this.userLogins = res.logins - this.userLoginsCount = res.logins.length + this.userInfo = res.adapterResponse.info[0] + this.userEmails = res.adapterResponse.emails + this.userEmailsCount = res.adapterResponse.emails.length + this.userRoles = res.adapterResponse.roles + this.userRolesCount = res.adapterResponse.roles.length + this.userLogins = res.adapterResponse.logins + this.userLoginsCount = res.adapterResponse.logins.length break } @@ -259,7 +260,7 @@ export class UserComponent implements OnInit { (userAr) => userAr.URI === user.URI ) } else { - const group = res.groups[0] + const group = res.adapterResponse.groups[0] this.userInfo = { URI: group.ID, @@ -272,9 +273,9 @@ export class UserComponent implements OnInit { } } - this.userData = res - this.userGroups = res.groups - this.userGroupsCount = res.groups.length + this.userData = res.adapterResponse + this.userGroups = res.adapterResponse.groups + this.userGroupsCount = res.adapterResponse.groups.length }) } } diff --git a/client/src/app/viewer/viewer.component.ts b/client/src/app/viewer/viewer.component.ts index 40116d8..722a1a9 100644 --- a/client/src/app/viewer/viewer.component.ts +++ b/client/src/app/viewer/viewer.component.ts @@ -37,6 +37,7 @@ import { DataFormat } from '../models/sas/common/DateFormat' import { Libinfo } from '../models/sas/common/Libinfo' import { LicenceService } from '../services/licence.service' import { Location } from '@angular/common' +import { RequestWrapperResponse } from '../models/request-wrapper/RequestWrapperResponse' @Component({ selector: 'app-viewer', @@ -292,8 +293,8 @@ export class ViewerComponent implements AfterContentInit, AfterViewInit { this.libinfo = null this.sasStoreService.refreshLibInfo(this.lib).then( - async (res: PublicRefreshlibinfoServiceResponse) => { - this.libinfo = res.libinfo + async (res: RequestWrapperResponse) => { + this.libinfo = res.adapterResponse.libinfo globals.viewer.libinfo = this.libinfo const library = this.libraries.find((x) => x.LIBRARYREF === this.lib) @@ -1127,8 +1128,8 @@ export class ViewerComponent implements AfterContentInit, AfterViewInit { await this.sasStoreService .viewLibs() - .then((res: PublicViewlibsServiceResponse) => { - this.libraries = res.saslibs + .then((res: RequestWrapperResponse) => { + this.libraries = res.adapterResponse.saslibs globals.viewer.libraries = this.libraries globals.viewer.startupSet = true diff --git a/client/src/app/xlmap/xlmap.component.ts b/client/src/app/xlmap/xlmap.component.ts index bee8bd0..0b84151 100644 --- a/client/src/app/xlmap/xlmap.component.ts +++ b/client/src/app/xlmap/xlmap.component.ts @@ -22,6 +22,7 @@ import { } from '../services' import { getCellAddress, getFinishingCell } from './utils/xl.utils' import { blobToFile, byteArrayToBinaryString } from './utils/file.utils' +import { UploadFileResponse } from '../models/UploadFile' interface XLMapRule { XLMAP_ID: string @@ -340,9 +341,9 @@ export class XLMapComponent implements AfterContentInit, AfterViewInit, OnInit { .uploadFile(uploadUrl, filesToUpload, { table: this.selectedXLMap.targetDS }) - .then((res: any) => { - if (res.sasjsAbort) { - const abortRes = res + .then((res: UploadFileResponse) => { + if (res.adapterResponse.sasjsAbort) { + const abortRes = res.adapterResponse const abortMsg = abortRes.sasjsAbort[0].MSG const macMsg = abortRes.sasjsAbort[0].MAC @@ -351,14 +352,14 @@ export class XLMapComponent implements AfterContentInit, AfterViewInit, OnInit { SYSERRORTEXT: abortRes.SYSERRORTEXT, MAC: macMsg }) - } else if (res.sasparams) { - const params = res.sasparams[0] + } else if (res.adapterResponse.sasparams) { + const params = res.adapterResponse.sasparams[0] const tableId = params.DSID this.router.navigateByUrl('/stage/' + tableId) } }) .catch((err: any) => { - this.eventService.catchResponseError('file upload', err) + this.eventService.catchResponseError('file upload', err.response) }) .finally(() => { this.status = Status.ReadyToSubmit