fix: unnecessary getsubmits call removed
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// Marks this file as an ES module (rather than a global script) so its
|
||||
// top-level consts don't collide, under the TS type-checker, with the same
|
||||
// names declared in other spec files — see e.g. stage.cy.ts, which gets
|
||||
// this for free via a real import.
|
||||
export {}
|
||||
|
||||
const hostUrl = Cypress.env('hosturl')
|
||||
const appLocation = Cypress.env('appLocation')
|
||||
const longerCommandTimeout = Cypress.env('longerCommandTimeout')
|
||||
|
||||
context('submitted-details tests: ', function () {
|
||||
this.beforeAll(() => {
|
||||
cy.loginAndUpdateValidKey(true)
|
||||
})
|
||||
|
||||
it('1 | clicking an open submit loads its diffs with a single postdata request', () => {
|
||||
// Count every STP request the app makes during the test.
|
||||
// The STP URL is `stp/execute/?_program=...` - glob segments don't match
|
||||
// past `execute/` with a single `*`, so keep the glob within the path.
|
||||
cy.intercept('POST', '**/SASjsApi/stp/**').as('stpExecute')
|
||||
|
||||
cy.visit(`${hostUrl}${appLocation}/#/review/submitted`)
|
||||
cy.get('.app-loading', { timeout: longerCommandTimeout }).should(
|
||||
'not.exist'
|
||||
)
|
||||
|
||||
// the SUBMIT queue list must be rendered with at least one row
|
||||
cy.get('app-submitter clr-datagrid clr-dg-row', {
|
||||
timeout: longerCommandTimeout
|
||||
})
|
||||
.should('exist')
|
||||
.and('have.length.greaterThan', 0)
|
||||
|
||||
// route-based flow: clicking a row navigates to /review/submitted/:tableId
|
||||
// and triggers exactly one SHOW_DIFFS (auditors/postdata) request
|
||||
cy.get('app-submitter clr-datagrid clr-dg-row')
|
||||
.first()
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.url().should('include', '/review/submitted/')
|
||||
})
|
||||
|
||||
// wait for the diff table to render (the response was applied)
|
||||
cy.get('app-approve-details .card', { timeout: longerCommandTimeout })
|
||||
.should('exist')
|
||||
.should('be.visible')
|
||||
|
||||
// give any (incorrect) duplicate request time to surface
|
||||
cy.wait(3000)
|
||||
|
||||
cy.get('@stpExecute.all').then((allRequests: any) => {
|
||||
// the adapter posts multipart form data, so match on the _program
|
||||
// query param rather than the request body
|
||||
const postdataRequests = allRequests.filter((req: any) =>
|
||||
JSON.stringify(req.request.query || {}).includes('auditors/postdata')
|
||||
)
|
||||
expect(
|
||||
postdataRequests.length,
|
||||
'exactly one auditors/postdata SHOW_DIFFS request'
|
||||
).to.equal(1)
|
||||
|
||||
// the submit queue was already fetched to render the list - opening a
|
||||
// row must not fetch it again
|
||||
const getsubmitsRequests = allRequests.filter((req: any) =>
|
||||
JSON.stringify(req.request.query || {}).includes('editors/getsubmits')
|
||||
)
|
||||
expect(
|
||||
getsubmitsRequests.length,
|
||||
'no editors/getsubmits request after opening a submit'
|
||||
).to.equal(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -217,7 +217,9 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
public calcDiff() {
|
||||
if (!this.response) return
|
||||
// params-only responses (e.g. already reviewed submissions) carry no diff
|
||||
// tables - nothing to calculate, the details header still renders
|
||||
if (!this.response || !this.response.cols) return
|
||||
|
||||
let news = this.response.new
|
||||
let updates = this.response.updates
|
||||
@@ -355,26 +357,6 @@ export class ApproveDetailsComponent implements AfterViewInit, OnDestroy {
|
||||
this.submitArr.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
let diffs = {
|
||||
ACTION: 'SHOW_DIFFS',
|
||||
TABLE: this.tableId,
|
||||
DIFFTIME: new Date().toUTCString()
|
||||
}
|
||||
// show diffs and changes info in a same call
|
||||
this.sasStoreService
|
||||
.showDiffs(diffs, 'SASControlTable', 'auditors/postdata')
|
||||
.then((res: AuditorsPostdataSASResponse) => {
|
||||
let param = res.params[0]
|
||||
this.params = param
|
||||
this.response = res
|
||||
this.calcDiff()
|
||||
this.callChangesInfo(this.tableId)
|
||||
})
|
||||
.catch((err: any) => err)
|
||||
.finally(() => {
|
||||
this.loadingTable = true
|
||||
})
|
||||
}
|
||||
)
|
||||
if (typeof this.router.snapshot.params['tableId'] === 'undefined') {
|
||||
|
||||
@@ -68,6 +68,9 @@ export class SubmitterComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
public goToDetails(table_id: any) {
|
||||
// the details URL re-creates this component - carry the queue payload
|
||||
// over so it is not fetched again on mount
|
||||
this.sasStoreService.handoffSubmits(this.submitData)
|
||||
this.router.navigateByUrl('/review/submitted/' + table_id)
|
||||
}
|
||||
|
||||
@@ -83,14 +86,19 @@ export class SubmitterComponent implements OnInit, AfterViewInit {
|
||||
|
||||
this.itemsNum = 10
|
||||
try {
|
||||
let res = await this.sasStoreService.getSubmitts()
|
||||
// navigating from the submit list to a details URL re-creates this
|
||||
// component - take the queue payload carried over by that navigation
|
||||
// instead of fetching it again
|
||||
let fromsas: any = this.sasStoreService.takeSubmitsHandoff()
|
||||
|
||||
this.remained = res.fromsas.length
|
||||
if (!fromsas) {
|
||||
fromsas = (await this.sasStoreService.getSubmitts()).fromsas
|
||||
}
|
||||
|
||||
this.remained = fromsas.length
|
||||
if (this.remained > 0) {
|
||||
this.submitter = res.fromsas[0].SUBMITTED_BY_NM
|
||||
let submitterList: SubmitterData[] = res.fromsas.map(function (
|
||||
item: any
|
||||
) {
|
||||
this.submitter = fromsas[0].SUBMITTED_BY_NM
|
||||
let submitterList: SubmitterData[] = fromsas.map(function (item: any) {
|
||||
return {
|
||||
tableId: item.TABLE_ID,
|
||||
base: item.BASE_TABLE,
|
||||
@@ -100,7 +108,7 @@ export class SubmitterComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
})
|
||||
this.submitterList = submitterList
|
||||
this.submitData = res.fromsas
|
||||
this.submitData = fromsas
|
||||
|
||||
// Details page
|
||||
if (typeof tableIdParam !== 'undefined') {
|
||||
|
||||
@@ -35,6 +35,13 @@ export class SasStoreService {
|
||||
public setSubmit: Subject<any> = new Subject<any>()
|
||||
public setSubmitList: Subject<any> = new Subject<any>()
|
||||
|
||||
/**
|
||||
* Submit queue payload carried across the navigation from the submit
|
||||
* list to a details URL - the re-created list component renders it
|
||||
* without fetching the queue again.
|
||||
*/
|
||||
private submitsHandoff: Array<any> | null = null
|
||||
|
||||
constructor(
|
||||
private sasService: SasService,
|
||||
private helperService: HelperService,
|
||||
@@ -155,6 +162,24 @@ export class SasStoreService {
|
||||
.adapterResponse
|
||||
}
|
||||
|
||||
/**
|
||||
* Carries the fetched submit queue over to the details URL navigation,
|
||||
* so the re-created submit list component does not fetch it again.
|
||||
*/
|
||||
public handoffSubmits(fromsas: Array<any> | undefined) {
|
||||
this.submitsHandoff = fromsas || null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the submit queue carried by the current navigation, if any,
|
||||
* and clears it - it is only valid for the navigation that set it.
|
||||
*/
|
||||
public takeSubmitsHandoff(): Array<any> | null {
|
||||
const fromsas = this.submitsHandoff
|
||||
this.submitsHandoff = null
|
||||
return fromsas
|
||||
}
|
||||
|
||||
private libsPromise: Promise<any> | null = null
|
||||
|
||||
/**
|
||||
|
||||
@@ -327,8 +327,7 @@ function stageSubmission(opts) {
|
||||
libds,
|
||||
libref,
|
||||
dsn,
|
||||
submitted_by_nm:
|
||||
typeof _METAUSER !== 'undefined' && _METAUSER ? _METAUSER : 'sasdemo',
|
||||
submitted_by_nm: getDcUser(),
|
||||
submitted_on_dttm: Date.now() / 1000,
|
||||
headers,
|
||||
rows
|
||||
@@ -502,6 +501,13 @@ function webOutObj(rows, label, meta) {
|
||||
* the `_webout` variable that the SASjs Server reads.
|
||||
* Mirrors mv_webout(CLOSE).
|
||||
*/
|
||||
// Current user for MPE_SUBMIT writes/reads - mock equivalent of %mf_getuser().
|
||||
// SASjs Server predeclares _METAUSER for authenticated requests; the desktop
|
||||
// mode (no auth) leaves it undefined.
|
||||
function getDcUser() {
|
||||
return typeof _METAUSER !== 'undefined' && _METAUSER ? _METAUSER : 'sasdemo'
|
||||
}
|
||||
|
||||
function webOutClose() {
|
||||
const now = new Date()
|
||||
const pad = n => String(n).padStart(2, '0')
|
||||
@@ -510,7 +516,7 @@ function webOutClose() {
|
||||
'.' + String(now.getMilliseconds()).padStart(3,'0')
|
||||
|
||||
// Derive system vars from SASjs Server runtime variables where possible
|
||||
const mfGetuser = (typeof _METAUSER !== 'undefined') ? _METAUSER : 'sasdemo'
|
||||
const mfGetuser = getDcUser()
|
||||
const metaperson = (typeof _METAPERSON !== 'undefined') ? _METAPERSON : 'sasdemo'
|
||||
const sysprocmode = (typeof SASJSPROCESSMODE !== 'undefined') ? SASJSPROCESSMODE : 'Stored Program'
|
||||
|
||||
|
||||
@@ -8,13 +8,17 @@ eval(fs.readFileSync(nodePath.resolve(driveRoot, "files", appLoc, "services", "d
|
||||
const dcLibref = 'DC_JSLIB'
|
||||
const dataDir = nodePath.resolve(driveRoot, 'files', appLoc, 'data', dcLibref)
|
||||
|
||||
// Load MPE_SUBMIT
|
||||
// Load MPE_SUBMIT - open submits of the current user only (mirrors the
|
||||
// where clause of editors/getsubmits.sas: submitted_by_nm=&mf_getuser and
|
||||
// submit_status_cd='SUBMITTED')
|
||||
let fromsas = []
|
||||
try {
|
||||
const file = nodePath.resolve(dataDir, 'mpe_submit.json')
|
||||
const raw = fs.readFileSync(file, {encoding:'utf8'}).toString()
|
||||
const submitData = JSON.parse(raw)
|
||||
fromsas = submitData.rows.map(r => ({
|
||||
fromsas = submitData.rows
|
||||
.filter(r => r.SUBMIT_STATUS_CD === 'SUBMITTED' && r.SUBMITTED_BY_NM === getDcUser())
|
||||
.map(r => ({
|
||||
TABLE_ID: r.TABLE_ID,
|
||||
BASE_TABLE: r.BASE_LIB + '.' + r.BASE_DS,
|
||||
INPUT_VARS: r.INPUT_VARS,
|
||||
|
||||
@@ -64,7 +64,11 @@ if (dataDir) {
|
||||
const mpeTablesFile = nodePath.resolve(dataDir, 'mpe_tables.json')
|
||||
const mpeTablesRaw = fs.readFileSync(mpeTablesFile, {encoding:'utf8'}).toString()
|
||||
const mpeTables = JSON.parse(mpeTablesRaw)
|
||||
sasdatasets = mpeTables.rows.map(r => ({ LIBREF: r.libref, DSN: r.dsn }))
|
||||
// Filter out any malformed rows (e.g. missing libref/dsn) so the
|
||||
// sasdatasets list never contains empty objects.
|
||||
sasdatasets = mpeTables.rows
|
||||
.filter(r => r.libref && r.dsn)
|
||||
.map(r => ({ LIBREF: r.libref, DSN: r.dsn }))
|
||||
sasdatasets.sort((a, b) => a.DSN.localeCompare(b.DSN))
|
||||
} catch(err) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user