Merge pull request 'fix: adjust the col numbers in extracted data' (#76) from fix-complex-xl-upload into main
All checks were successful
Release / Build-production-and-ng-test (push) Successful in 4m53s
Release / Build-and-test-development (push) Successful in 8m34s
Release / release (push) Successful in 7m0s

Reviewed-on: #76
This commit is contained in:
allan 2024-02-12 09:58:42 +00:00
commit f13e909478
11 changed files with 239 additions and 67 deletions

View File

@ -186,24 +186,37 @@
} as libdsParsed" } as libdsParsed"
class="editor-title text-center mt-0-i" class="editor-title text-center mt-0-i"
> >
<clr-icon <clr-tooltip>
(click)="datasetInfo = true" <clr-icon
shape="info-circle" clrTooltipTrigger
class="is-highlight cursor-pointer" (click)="datasetInfo = true"
size="24" shape="info-circle"
></clr-icon> class="is-highlight cursor-pointer"
size="24"
></clr-icon>
<clr-icon <clr-icon
*ngIf="libdsParsed.tableName.includes('-FC')" *ngIf="libdsParsed.tableName.includes('-FC')"
shape="bolt" shape="bolt"
class="color-yellow" class="color-yellow"
></clr-icon> ></clr-icon>
<span clrTooltipTrigger>
{{ libdsParsed.libName }}.<a
class="mr-10"
[routerLink]="'/view/data/' + libds!"
>{{ libdsParsed.tableName.replace('-FC', '') }}</a
>
</span>
<clr-tooltip-content
clrPosition="bottom-left"
clrSize="lg"
*clrIfOpen
>
{{ this.dsNote }}
</clr-tooltip-content>
</clr-tooltip>
{{ libdsParsed.libName }}.<a
class="mr-10"
[routerLink]="'/view/data/' + libds!"
>{{ libdsParsed.tableName.replace('-FC', '') }}</a
>
<ng-container *ngIf="dataSource"> <ng-container *ngIf="dataSource">
<ng-container *ngIf="!zeroFilterRows"> <ng-container *ngIf="!zeroFilterRows">
({{ dataSource.length | thousandSeparator: ',' }} ({{ dataSource.length | thousandSeparator: ',' }}

View File

@ -121,6 +121,7 @@ export class EditorComponent implements OnInit, AfterViewInit {
datasetInfo: boolean = false datasetInfo: boolean = false
dsmeta: DSMeta[] = [] dsmeta: DSMeta[] = []
dsNote = ''
viewboxes: boolean = false viewboxes: boolean = false
@ -2986,6 +2987,20 @@ export class EditorComponent implements OnInit, AfterViewInit {
this.cols = response.data.cols this.cols = response.data.cols
this.dsmeta = response.data.dsmeta this.dsmeta = response.data.dsmeta
const notes = this.dsmeta.find((item) => item.NAME === 'NOTES')
const longDesc = this.dsmeta.find((item) => item.NAME === 'DD_LONGDESC')
const shortDesc = this.dsmeta.find((item) => item.NAME === 'DD_SHORTDESC')
if (notes && notes.VALUE) {
this.dsNote = notes.VALUE
} else if (longDesc && longDesc.VALUE) {
this.dsNote = longDesc.VALUE
} else if (shortDesc && shortDesc.VALUE) {
this.dsNote = shortDesc.VALUE
} else {
this.dsNote = ''
}
const hot: Handsontable = this.hotInstance const hot: Handsontable = this.hotInstance
const approvers: Approver[] = response.data.approvers const approvers: Approver[] = response.data.approvers

View File

@ -358,36 +358,49 @@
</section> </section>
<div class="title-col clr-col-auto clr-flex-column clr-flex-sm-row"> <div class="title-col clr-col-auto clr-flex-column clr-flex-sm-row">
<clr-icon
(click)="datasetInfo = true"
shape="info-circle"
class="is-highlight cursor-pointer"
size="24"
></clr-icon>
<clr-icon
*ngIf="tableTitle?.includes('-FC')"
shape="bolt"
class="color-yellow mt-5 mr-5"
></clr-icon>
<h3 <h3
*ngIf="tableTitle && tableTitle.length > 0" class="viewerTitle clr-flex-column d-flex clr-flex-sm-row clr-align-items-center clr-justify-content-center"
class="viewerTitle clr-flex-column d-flex clr-flex-sm-row clr-align-items-center"
> >
{{ tableTitle?.replace('-FC', '') }} <clr-tooltip class="d-flex">
<clr-icon
clrTooltipTrigger
(click)="datasetInfo = true"
shape="info-circle"
class="is-highlight cursor-pointer"
size="24"
></clr-icon>
<span *ngIf="numberOfRows !== null"> <clr-icon
({{ numberOfRows | thousandSeparator: ',' }} *ngIf="tableTitle?.includes('-FC')"
{{ numberOfRows! === 1 ? 'row' : 'rows' }}, {{ filterCols.length shape="bolt"
}}{{ filterCols.length === 1 ? ' col' : ' cols' }}) class="color-yellow mt-5 mr-5"
</span> ></clr-icon>
<clr-icon <span clrTooltipTrigger *ngIf="tableTitle && tableTitle.length > 0">
(click)="reloadTableData()" {{ tableTitle?.replace('-FC', '') }}
class="refresh-table" </span>
shape="refresh" <clr-tooltip-content
></clr-icon> clrPosition="bottom-left"
clrSize="lg"
*clrIfOpen
>
{{ this.dsNote }}
</clr-tooltip-content>
</clr-tooltip>
<ng-container *ngIf="tableTitle && tableTitle.length > 0">
<span *ngIf="numberOfRows !== null">
({{ numberOfRows | thousandSeparator: ',' }}
{{ numberOfRows! === 1 ? 'row' : 'rows' }}, {{ filterCols.length
}}{{ filterCols.length === 1 ? ' col' : ' cols' }})
</span>
<clr-icon
(click)="reloadTableData()"
class="refresh-table"
shape="refresh"
></clr-icon>
</ng-container>
</h3> </h3>
</div> </div>

View File

@ -95,6 +95,7 @@ export class ViewerComponent implements AfterContentInit, AfterViewInit {
public $dataFormats: $DataFormats | null = null public $dataFormats: $DataFormats | null = null
public datasetInfo: boolean = false public datasetInfo: boolean = false
public dsmeta: DSMeta[] = [] public dsmeta: DSMeta[] = []
public dsNote = ''
public licenceState = this.licenceService.licenceState public licenceState = this.licenceService.licenceState
public Infinity = Infinity public Infinity = Infinity
@ -246,6 +247,7 @@ export class ViewerComponent implements AfterContentInit, AfterViewInit {
this.hotTable.data = res.viewdata this.hotTable.data = res.viewdata
this.$dataFormats = res.$viewdata this.$dataFormats = res.$viewdata
this.dsmeta = res.dsmeta this.dsmeta = res.dsmeta
this.setDSNote()
this.numberOfRows = res.sasparams[0].NOBS this.numberOfRows = res.sasparams[0].NOBS
this.queryText = res.sasparams[0].FILTER_TEXT this.queryText = res.sasparams[0].FILTER_TEXT
this.headerPks = res.sasparams[0].PK_FIELDS.split(' ') this.headerPks = res.sasparams[0].PK_FIELDS.split(' ')
@ -803,6 +805,7 @@ export class ViewerComponent implements AfterContentInit, AfterViewInit {
this.hotTable.data = res.viewdata this.hotTable.data = res.viewdata
this.$dataFormats = res.$viewdata this.$dataFormats = res.$viewdata
this.dsmeta = res.dsmeta this.dsmeta = res.dsmeta
this.setDSNote()
this.queryText = res.sasparams[0].FILTER_TEXT this.queryText = res.sasparams[0].FILTER_TEXT
let columns: any[] = [] let columns: any[] = []
let colArr = [] let colArr = []
@ -1016,6 +1019,22 @@ export class ViewerComponent implements AfterContentInit, AfterViewInit {
this.sasStoreService.removeClause() this.sasStoreService.removeClause()
} }
private setDSNote() {
const notes = this.dsmeta.find((item) => item.NAME === 'NOTES')
const longDesc = this.dsmeta.find((item) => item.NAME === 'DD_LONGDESC')
const shortDesc = this.dsmeta.find((item) => item.NAME === 'DD_SHORTDESC')
if (notes && notes.VALUE) {
this.dsNote = notes.VALUE
} else if (longDesc && longDesc.VALUE) {
this.dsNote = longDesc.VALUE
} else if (shortDesc && shortDesc.VALUE) {
this.dsNote = shortDesc.VALUE
} else {
this.dsNote = ''
}
}
private setupHot() { private setupHot() {
setTimeout(() => { setTimeout(() => {
if (!this.loadingTableView && this.libDataset) { if (!this.loadingTableView && this.libDataset) {

View File

@ -385,34 +385,39 @@ export class XLMapComponent implements AfterContentInit, AfterViewInit, OnInit {
const start = getCellAddress(rule.XLMAP_START, arrayOfObjects) const start = getCellAddress(rule.XLMAP_START, arrayOfObjects)
const finish = getFinishingCell(start, rule.XLMAP_FINISH, arrayOfObjects) const finish = getFinishingCell(start, rule.XLMAP_FINISH, arrayOfObjects)
const range = `${start}:${finish}` const a1Range = `${start}:${finish}`
const range = XLSX.utils.decode_range(a1Range)
const rangedData = <any[]>XLSX.utils.sheet_to_json(sheet, { const rangedData = <any[]>XLSX.utils.sheet_to_json(sheet, {
raw: true, raw: true,
range: range, range: a1Range,
header: 'A', header: 'A',
blankrows: true blankrows: true
}) })
for (let i = 0; i < rangedData.length; i++) { for (let i = 0; i < rangedData.length; i++) {
const row = rangedData[i] const row = rangedData[i]
// Get the keys of the object (excluding '__rowNum__')
const keys = Object.keys(row).filter((key) => key !== '__rowNum__')
for (let j = 0; j < keys.length; j++) { // `range.s.c` is the index of first column in the range
const key = keys[j] // `range.e.c` is the index of last column in the range
const val = row[key] // we'll iterate from first column to last column and
// extract value where defined and push to extracted data array
for (let j = range.s.c, x = 0; j <= range.e.c; j++, x++) {
const col = XLSX.utils.encode_col(j)
// in excel's R1C1 notation indexing starts from 1 but in JS it starts from 0 if (col in row) {
// therefore, we'll have to add 1 to rows and cols // in excel's R1C1 notation indexing starts from 1 but in JS it starts from 0
extractedData.push({ // therefore, we'll have to add 1 to rows and cols
LOAD_REF: '0', extractedData.push({
XLMAP_ID: rule.XLMAP_ID, LOAD_REF: '0',
XLMAP_RANGE_ID: rule.XLMAP_RANGE_ID, XLMAP_ID: rule.XLMAP_ID,
ROW_NO: i + 1, XLMAP_RANGE_ID: rule.XLMAP_RANGE_ID,
COL_NO: j + 1, ROW_NO: i + 1,
VALUE_TXT: val COL_NO: x + 1,
}) VALUE_TXT: row[col]
})
}
} }
} }
}) })

View File

@ -18,4 +18,4 @@ In any case, you must not make any such use of this software as to develop softw
UNLESS EXPRESSLY AGREED OTHERWISE, 4GL APPS PROVIDES THIS SOFTWARE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, AND IN NO EVENT AND UNDER NO LEGAL THEORY, SHALL 4GL APPS BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER ARISING FROM USE OR INABILITY TO USE THIS SOFTWARE. UNLESS EXPRESSLY AGREED OTHERWISE, 4GL APPS PROVIDES THIS SOFTWARE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, AND IN NO EVENT AND UNDER NO LEGAL THEORY, SHALL 4GL APPS BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER ARISING FROM USE OR INABILITY TO USE THIS SOFTWARE.
` `

View File

@ -0,0 +1,70 @@
/**
@file
@brief Gets table metadata
@details Runs mp_dsmeta and adds datadictionary info
<h4> SAS Macros </h4>
@li mp_dsmeta.sas
@version 9.2
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
%macro mpe_dsmeta(libds, outds=dsmeta);
%local ddsd ddld notes lenstmt;
%let lenstmt=length ods_table $18 name $100 value $1000;
%let libds=%upcase(&libds);
%mp_dsmeta(&libds, outds=&outds)
data _null_;
set &mpelib..mpe_datadictionary;
where &dc_dttmtfmt < tx_to & dd_source=%upcase("&libds") & dd_type='TABLE';
call symputx('ddsd',dd_shortdesc,'l');
call symputx('ddld',dd_longdesc,'l');
run;
data &outds;
&lenstmt;
if last then do;
ODS_TABLE='MPE_DATADICTIONARY';
NAME='DD_SHORTDESC';
VALUE="&ddsd";
output;
NAME='DD_LONGDESC';
VALUE="&ddld";
output;
end;
set &outds end=last;
output;
run;
data _data_;
set &mpelib..mpe_tables;
where libref="%scan(&libds,1,.)"
& dsn="%scan(&libds,2,.)"
& &dc_dttmtfmt<tx_to;
&lenstmt;
ODS_TABLE='MPE_TABLES';
array c _character_;
array n _numeric_;
do over c;
name=upcase(vname(c));
value=c;
output;
end;
do over n;
name=upcase(vname(n));
value=cats(n);
output;
end;
keep ods_table name value;
run;
proc append base=&outds data=&syslast;
run;
%mend mpe_dsmeta;

View File

@ -0,0 +1,37 @@
/**
@file
@brief Testing mpe_dsmeta macro
@details Checking functionality of mpe_dsmeta.sas macro
<h4> SAS Macros </h4>
@li mp_assertdsobs.sas
@li mp_assertscope.sas
@li mpe_dsmeta.sas
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
/* run the macro*/
%mp_assertscope(SNAPSHOT)
%mpe_dsmeta(&mpelib..mpe_security, outds=test1)
%mp_assertscope(COMPARE,
desc=Checking macro variables against previous snapshot
)
data work.test1;
set work.test1;
where ods_table in ('MPE_DATADICTIONARY','MPE_TABLES');
putlog (_all_)(=);
run;
%mp_assertdsobs(work.test1,
desc=Test 1 - 27 records returned,
test=EQUALS 27,
outds=work.test_results
)

View File

@ -14,7 +14,7 @@
<h5> sasdata </h5> <h5> sasdata </h5>
<h5> sasparams </h5> <h5> sasparams </h5>
Contains info on the request. One row is returned. Contains info on the request. One row is returned.
@li CLS_FLG - set to 0 if there are no CLS rules (everything should be editable) @li CLS_FLG - set to 0 if there are no CLS rules (everything editable)
else set to 1 (CLS rules exist) else set to 1 (CLS rules exist)
@li ISMAP - set to 1 if the target DS is an excel map target, else 0 @li ISMAP - set to 1 if the target DS is an excel map target, else 0
@ -56,12 +56,12 @@
@li mf_wordsinstr1butnotstr2.sas @li mf_wordsinstr1butnotstr2.sas
@li mp_abort.sas @li mp_abort.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_dsmeta.sas
@li mp_getcols.sas @li mp_getcols.sas
@li mp_getmaxvarlengths.sas @li mp_getmaxvarlengths.sas
@li mp_validatecol.sas @li mp_validatecol.sas
@li mpe_accesscheck.sas @li mpe_accesscheck.sas
@li mpe_columnlevelsecurity.sas @li mpe_columnlevelsecurity.sas
@li mpe_dsmeta.sas
@li mpe_getlabels.sas @li mpe_getlabels.sas
@li mpe_filtermaster.sas @li mpe_filtermaster.sas
@li mpe_runhook.sas @li mpe_runhook.sas
@ -665,7 +665,7 @@ data xl_rules;
keep xl_column xl_rule; keep xl_column xl_rule;
run; run;
%mp_dsmeta(&libds, outds=dsmeta) %mpe_dsmeta(&libds, outds=dsmeta)
/* send to the client */ /* send to the client */
%webout(OPEN) %webout(OPEN)

View File

@ -21,7 +21,7 @@
data _null_; data _null_;
file &f1 termstr=crlf; file &f1 termstr=crlf;
put 'XLMAP_ID:$char12.'; put 'XLMAP_ID:$char12.';
put "Sample"; put "BASEL-KM1";
run; run;
%mx_testservice(&_program, %mx_testservice(&_program,
@ -38,7 +38,7 @@ run;
%mp_assertdsobs(work.xlmaprules, %mp_assertdsobs(work.xlmaprules,
test=ATLEAST 2, test=ATLEAST 2,
desc=Checking successful return of at least 2 rules for the Sample map, desc=Checking successful return of at least 2 rules for the BASEL-KM1 map,
outds=work.test_results outds=work.test_results
) )

View File

@ -44,13 +44,13 @@
@li mf_verifymacvars.sas @li mf_verifymacvars.sas
@li mp_abort.sas @li mp_abort.sas
@li mp_cntlout.sas @li mp_cntlout.sas
@li mp_dsmeta.sas
@li mp_getcols.sas @li mp_getcols.sas
@li mp_getpk.sas @li mp_getpk.sas
@li mp_jsonout.sas @li mp_jsonout.sas
@li mp_searchdata.sas @li mp_searchdata.sas
@li mp_validatecol.sas @li mp_validatecol.sas
@li mpe_columnlevelsecurity.sas @li mpe_columnlevelsecurity.sas
@li mpe_dsmeta.sas
@li mpe_filtermaster.sas @li mpe_filtermaster.sas
@ -351,7 +351,7 @@ run;
%mp_getcols(&libds, outds=cols) %mp_getcols(&libds, outds=cols)
%mp_dsmeta(&libds, outds=dsmeta) %mpe_dsmeta(&libds, outds=dsmeta)
%webout(OPEN) %webout(OPEN)
%webout(OBJ,cls_rules) %webout(OBJ,cls_rules)