src/app/xlmap/xlmap.component.ts
AfterContentInit
AfterViewInit
OnInit
| encapsulation | ViewEncapsulation.None |
| selector | app-xlmap |
| styleUrls | ./xlmap.component.scss |
| templateUrl | ./xlmap.component.html |
Properties |
|
Methods |
|
HostBindings |
constructor(eventService: EventService, licenceService: LicenceService, loggerService: LoggerService, route: ActivatedRoute, router: Router, sasStoreService: SasStoreService, sasService: SasService)
|
||||||||||||||||||||||||
|
Defined in src/app/xlmap/xlmap.component.ts:181
|
||||||||||||||||||||||||
|
Parameters :
|
| class.content-container |
Type : boolean
|
Default value : true
|
|
Defined in src/app/xlmap/xlmap.component.ts:70
|
| Public afterGetColHeader |
afterGetColHeader(column: number, th: any)
|
|
Defined in src/app/xlmap/xlmap.component.ts:193
|
|
Returns :
void
|
| Private buildHotSettings |
buildHotSettings()
|
|
Defined in src/app/xlmap/xlmap.component.ts:148
|
|
Returns :
Handsontable.GridSettings
|
| Public discardExtractedData |
discardExtractedData()
|
|
Defined in src/app/xlmap/xlmap.component.ts:328
|
|
Returns :
void
|
| Public extractData | ||||||
extractData(wb: XLSX.WorkBook)
|
||||||
|
Defined in src/app/xlmap/xlmap.component.ts:418
|
||||||
|
Parameters :
Returns :
void
|
| Public fileOverBase | ||||||||
fileOverBase(e: boolean)
|
||||||||
|
Defined in src/app/xlmap/xlmap.component.ts:249
|
||||||||
|
Called by FileDropDirective
Parameters :
Returns :
void
|
| Public getCellConfiguration |
getCellConfiguration()
|
|
Defined in src/app/xlmap/xlmap.component.ts:233
|
|
Returns :
{ readOnly: boolean; }
|
| Public getFileDesc | ||||||||||||
getFileDesc(event: any, dropped: unknown)
|
||||||||||||
|
Defined in src/app/xlmap/xlmap.component.ts:253
|
||||||||||||
|
Parameters :
Returns :
void
|
| Public isActiveXLMap | ||||||
isActiveXLMap(id: string)
|
||||||
|
Defined in src/app/xlmap/xlmap.component.ts:224
|
||||||
|
Parameters :
Returns :
boolean
|
| Private load |
load()
|
|
Defined in src/app/xlmap/xlmap.component.ts:508
|
|
Returns :
void
|
| Public maxWidthChecker |
maxWidthChecker(width: any, col: any)
|
|
Defined in src/app/xlmap/xlmap.component.ts:228
|
|
Returns :
any
|
| ngAfterContentInit |
ngAfterContentInit()
|
|
Defined in src/app/xlmap/xlmap.component.ts:536
|
|
Returns :
void
|
| ngAfterViewInit |
ngAfterViewInit()
|
|
Defined in src/app/xlmap/xlmap.component.ts:532
|
|
Returns :
void
|
| ngOnInit |
ngOnInit()
|
|
Defined in src/app/xlmap/xlmap.component.ts:523
|
|
Returns :
void
|
| Public onShowUploadModal |
onShowUploadModal()
|
|
Defined in src/app/xlmap/xlmap.component.ts:241
|
|
Returns :
void
|
| Public rowHeaders |
rowHeaders()
|
|
Defined in src/app/xlmap/xlmap.component.ts:237
|
|
Returns :
string
|
| Private setSelectedTab | ||||||
setSelectedTab(tab: Tabs)
|
||||||
|
Defined in src/app/xlmap/xlmap.component.ts:178
|
||||||
|
Parameters :
Returns :
void
|
| Public submit |
submit()
|
|
Defined in src/app/xlmap/xlmap.component.ts:353
|
|
Returns :
void
|
| Public submitExcel |
submitExcel()
|
|
Defined in src/app/xlmap/xlmap.component.ts:344
|
|
Submits attached excel file that is in preview mode
Returns :
void
|
| Async viewXLMapRules |
viewXLMapRules()
|
|
Defined in src/app/xlmap/xlmap.component.ts:487
|
|
Returns :
any
|
| Public xlmapListOnFilter |
xlmapListOnFilter()
|
|
Defined in src/app/xlmap/xlmap.component.ts:213
|
|
Returns :
void
|
| Public xlmapOnClick | ||||||
xlmapOnClick(xlmap: XLMapListItem)
|
||||||
|
Defined in src/app/xlmap/xlmap.component.ts:198
|
||||||
|
Parameters :
Returns :
void
|
| contentContainerClass |
Type : unknown
|
Default value : true
|
Decorators :
@HostBinding('class.content-container')
|
|
Defined in src/app/xlmap/xlmap.component.ts:70
|
| Public filename |
Type : string
|
Default value : ''
|
|
Defined in src/app/xlmap/xlmap.component.ts:131
|
| fileUploadInputCompList |
Type : QueryList<ElementRef>
|
Default value : new QueryList()
|
Decorators :
@ViewChildren('fileUploadInput')
|
|
Defined in src/app/xlmap/xlmap.component.ts:72
|
| Public hasBaseDropZoneOver |
Type : unknown
|
Default value : false
|
|
Defined in src/app/xlmap/xlmap.component.ts:130
|
| Public hotTableLicenseKey |
Type : string | undefined
|
Default value : undefined
|
|
Defined in src/app/xlmap/xlmap.component.ts:138
|
| Public hotTableMaxRows |
Type : unknown
|
Default value : this.licenceState.value.viewer_rows_allowed || Infinity
|
|
Defined in src/app/xlmap/xlmap.component.ts:139
|
| hotTableSettings |
Type : unknown
|
Default value : signal<Handsontable.GridSettings>(this.buildHotSettings())
|
|
Defined in src/app/xlmap/xlmap.component.ts:146
|
| Public isLoading |
Type : unknown
|
Default value : false
|
|
Defined in src/app/xlmap/xlmap.component.ts:84
|
| Public isLoadingDesc |
Type : string
|
Default value : ''
|
|
Defined in src/app/xlmap/xlmap.component.ts:85
|
| Public licenceState |
Type : unknown
|
Default value : this.licenceService.licenceState
|
|
Defined in src/app/xlmap/xlmap.component.ts:136
|
| Public rulesSource |
Type : unknown
|
Default value : globals.dcLib + '.MPE_XLMAP_RULES'
|
|
Defined in src/app/xlmap/xlmap.component.ts:78
|
| Public searchString |
Type : string
|
Default value : ''
|
|
Defined in src/app/xlmap/xlmap.component.ts:82
|
| Public selectedTab |
Type : unknown
|
Default value : Tabs.Rules
|
|
Defined in src/app/xlmap/xlmap.component.ts:77
|
| Public selectedXLMap |
Type : XLMapListItem | undefined
|
Default value : undefined
|
|
Defined in src/app/xlmap/xlmap.component.ts:81
|
| Public showUploadModal |
Type : unknown
|
Default value : false
|
|
Defined in src/app/xlmap/xlmap.component.ts:129
|
| Public status |
Type : unknown
|
Default value : Status.NoMapSelected
|
|
Defined in src/app/xlmap/xlmap.component.ts:86
|
| StatusEnum |
Type : unknown
|
Default value : Status
|
|
Defined in src/app/xlmap/xlmap.component.ts:74
|
| Public submitLimitNotice |
Type : unknown
|
Default value : false
|
|
Defined in src/app/xlmap/xlmap.component.ts:132
|
| TabsEnum |
Type : unknown
|
Default value : Tabs
|
|
Defined in src/app/xlmap/xlmap.component.ts:75
|
| Public uploader |
Type : FileUploader
|
Default value : new FileUploader()
|
|
Defined in src/app/xlmap/xlmap.component.ts:134
|
| Public xlData |
Type : XLUploadEntry[]
|
Default value : []
|
|
Defined in src/app/xlmap/xlmap.component.ts:127
|
| Public xlmapRules |
Type : XLMapRule[]
|
Default value : []
|
|
Defined in src/app/xlmap/xlmap.component.ts:109
|
| Public xlmapRulesColumns |
Type : []
|
Default value : [
{
data: 'XLMAP_SHEET'
},
{
data: 'XLMAP_RANGE_ID'
},
{
data: 'XLMAP_START'
},
{
data: 'XLMAP_FINISH'
}
]
|
|
Defined in src/app/xlmap/xlmap.component.ts:94
|
| Public xlmapRulesHeaders |
Type : []
|
Default value : [
'XLMAP_SHEET',
'XLMAP_RANGE_ID',
'XLMAP_START',
'XLMAP_FINISH'
]
|
|
Defined in src/app/xlmap/xlmap.component.ts:88
|
| Public xlmaps |
Type : XLMapListItem[]
|
Default value : []
|
|
Defined in src/app/xlmap/xlmap.component.ts:80
|
| Public xlmapsLoading |
Type : unknown
|
Default value : true
|
|
Defined in src/app/xlmap/xlmap.component.ts:83
|
| Public xlUploadColumns |
Type : []
|
Default value : [
{
data: 'XLMAP_RANGE_ID'
},
{
data: 'ROW_NO'
},
{
data: 'COL_NO'
},
{
data: 'VALUE_TXT'
}
]
|
|
Defined in src/app/xlmap/xlmap.component.ts:112
|
| Public xlUploadHeader |
Type : []
|
Default value : ['XLMAP_RANGE_ID', 'ROW_NO', 'COL_NO', 'VALUE_TXT']
|
|
Defined in src/app/xlmap/xlmap.component.ts:111
|
import {
AfterContentInit,
AfterViewInit,
Component,
ElementRef,
HostBinding,
OnInit,
QueryList,
signal,
ViewChildren,
ViewEncapsulation
} from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { UploadFile } from '@sasjs/adapter'
import * as XLSX from '@sheet/crypto'
import { XLMapListItem, globals } from '../_globals'
import { FileUploader } from '../models/FileUploader.class'
import {
EventService,
LicenceService,
LoggerService,
SasService,
SasStoreService
} from '../services'
import { getCellAddress, getFinishingCell } from './utils/xl.utils'
import { blobToFile, byteArrayToBinaryString } from './utils/file.utils'
import Handsontable from 'handsontable'
import { UploadFileResponse } from '../models/UploadFile'
interface XLMapRule {
XLMAP_ID: string
XLMAP_SHEET: string
XLMAP_RANGE_ID: string
XLMAP_START: string
XLMAP_FINISH: string
}
interface XLUploadEntry {
LOAD_REF: string
XLMAP_ID: string
XLMAP_RANGE_ID: string
ROW_NO: number
COL_NO: number
VALUE_TXT: string
}
enum Status {
NoMapSelected,
FetchingRules,
ReadyToUpload,
ExtractingData,
ReadyToSubmit,
SubmittingExtractedData,
Submitting
}
enum Tabs {
Rules,
Data
}
@Component({
selector: 'app-xlmap',
templateUrl: './xlmap.component.html',
styleUrls: ['./xlmap.component.scss'],
encapsulation: ViewEncapsulation.None,
standalone: false
})
export class XLMapComponent implements AfterContentInit, AfterViewInit, OnInit {
@HostBinding('class.content-container') contentContainerClass = true
@ViewChildren('fileUploadInput')
fileUploadInputCompList: QueryList<ElementRef> = new QueryList()
StatusEnum = Status
TabsEnum = Tabs
public selectedTab = Tabs.Rules
public rulesSource = globals.dcLib + '.MPE_XLMAP_RULES'
public xlmaps: XLMapListItem[] = []
public selectedXLMap: XLMapListItem | undefined = undefined
public searchString = ''
public xlmapsLoading = true
public isLoading = false
public isLoadingDesc = ''
public status = Status.NoMapSelected
public xlmapRulesHeaders = [
'XLMAP_SHEET',
'XLMAP_RANGE_ID',
'XLMAP_START',
'XLMAP_FINISH'
]
public xlmapRulesColumns = [
{
data: 'XLMAP_SHEET'
},
{
data: 'XLMAP_RANGE_ID'
},
{
data: 'XLMAP_START'
},
{
data: 'XLMAP_FINISH'
}
]
public xlmapRules: XLMapRule[] = []
public xlUploadHeader = ['XLMAP_RANGE_ID', 'ROW_NO', 'COL_NO', 'VALUE_TXT']
public xlUploadColumns = [
{
data: 'XLMAP_RANGE_ID'
},
{
data: 'ROW_NO'
},
{
data: 'COL_NO'
},
{
data: 'VALUE_TXT'
}
]
public xlData: XLUploadEntry[] = []
public showUploadModal = false
public hasBaseDropZoneOver = false
public filename = ''
public submitLimitNotice = false
public uploader: FileUploader = new FileUploader()
public licenceState = this.licenceService.licenceState
public hotTableLicenseKey: string | undefined = undefined
public hotTableMaxRows =
this.licenceState.value.viewer_rows_allowed || Infinity
// Stable settings reference so the HOT v17 wrapper doesn't re-run
// updateSettings on every change-detection tick (the previous getter returned a
// new object each call, causing an infinite render loop / freeze). Rebuilt only
// when the selected tab, or the license, changes (see setSelectedTab + ngOnInit).
hotTableSettings = signal<Handsontable.GridSettings>(this.buildHotSettings())
private buildHotSettings(): Handsontable.GridSettings {
return {
multiColumnSorting: true,
viewportRowRenderingOffset: 50,
colHeaders:
this.selectedTab === this.TabsEnum.Rules
? this.xlmapRulesHeaders
: this.xlUploadHeader,
columns:
this.selectedTab === this.TabsEnum.Rules
? this.xlmapRulesColumns
: this.xlUploadColumns,
filters: true,
height: '100%',
stretchH: 'all',
afterGetColHeader: this.afterGetColHeader,
modifyColWidth: this.maxWidthChecker,
cells: this.getCellConfiguration,
maxRows: this.hotTableMaxRows,
manualColumnResize: true,
rowHeaders: this.rowHeaders,
rowHeaderWidth: 15,
rowHeights: 20,
licenseKey: this.hotTableLicenseKey,
className: 'htDark',
theme: 'ht-theme-classic'
}
}
// Single place that changes the active tab so the settings signal stays in sync.
private setSelectedTab(tab: Tabs) {
this.selectedTab = tab
this.hotTableSettings.set(this.buildHotSettings())
}
constructor(
private eventService: EventService,
private licenceService: LicenceService,
private loggerService: LoggerService,
private route: ActivatedRoute,
private router: Router,
private sasStoreService: SasStoreService,
private sasService: SasService
) {}
public afterGetColHeader(column: number, th: any) {
// Dark mode
th.classList.add(globals.handsontable.darkTableHeaderClass)
}
public xlmapOnClick(xlmap: XLMapListItem) {
if (xlmap.id !== this.selectedXLMap?.id) {
this.selectedXLMap = xlmap
this.xlData = []
this.filename = ''
this.uploader.queue = []
if (this.fileUploadInputCompList.first) {
this.fileUploadInputCompList.first.nativeElement.value = ''
}
this.setSelectedTab(Tabs.Rules)
this.viewXLMapRules()
this.router.navigateByUrl('/home/excel-maps/' + xlmap.id)
}
}
public xlmapListOnFilter() {
if (this.searchString.length > 0) {
const array: XLMapListItem[] = globals.xlmaps
this.xlmaps = array.filter((item) =>
item.id.toLowerCase().includes(this.searchString.toLowerCase())
)
} else {
this.xlmaps = globals.xlmaps
}
}
public isActiveXLMap(id: string) {
return this.selectedXLMap?.id === id
}
public maxWidthChecker(width: any, col: any) {
if (width > 200) return 200
else return width
}
public getCellConfiguration() {
return { readOnly: true }
}
public rowHeaders() {
return ' '
}
public onShowUploadModal() {
this.showUploadModal = true
}
/**
* Called by FileDropDirective
* @param e true if file is dragged over the drop zone
*/
public fileOverBase(e: boolean): void {
this.hasBaseDropZoneOver = e
}
public getFileDesc(event: any, dropped = false) {
const file = dropped ? event[0] : event.target.files[0]
if (!file) return
const filename = file.name
this.filename = filename
const fileType = filename.slice(
filename.lastIndexOf('.') + 1,
filename.lastIndexOf('.') + 4
)
if (fileType.toLowerCase() === 'xls') {
this.showUploadModal = false
this.isLoading = true
this.isLoadingDesc = 'Extracting Data'
this.status = Status.ExtractingData
const reader = new FileReader()
reader.onload = async (theFile: any) => {
/* read workbook */
const bstr = byteArrayToBinaryString(theFile.target.result)
let wb: XLSX.WorkBook | undefined = undefined
const xlsxOptions: XLSX.ParsingOptions = {
type: 'binary',
cellDates: false,
cellFormula: true,
cellStyles: true,
cellNF: false,
cellText: false
}
try {
wb = XLSX.read(bstr, {
...xlsxOptions
})
} catch (err: any) {
this.eventService.showAbortModal(
null,
err,
undefined,
'Error reading file'
)
}
if (!wb) {
this.isLoading = false
this.isLoadingDesc = ''
this.status = Status.ReadyToUpload
this.uploader.queue.pop()
return
}
this.extractData(wb)
return
}
reader.readAsArrayBuffer(file)
} else {
this.isLoading = false
this.isLoadingDesc = ''
this.status = Status.ReadyToUpload
this.showUploadModal = true
this.uploader.queue.pop()
const abortMsg =
'Invalid file type "<b>' +
this.filename +
'</b>". Please upload excel file.'
this.eventService.showAbortModal(null, abortMsg)
}
}
public discardExtractedData() {
this.isLoading = false
this.isLoadingDesc = ''
this.status = Status.ReadyToUpload
this.xlData = []
this.setSelectedTab(Tabs.Rules)
this.filename = ''
this.uploader.queue = []
if (this.fileUploadInputCompList.first) {
this.fileUploadInputCompList.first.nativeElement.value = ''
}
}
/**
* Submits attached excel file that is in preview mode
*/
public submitExcel() {
if (this.licenceState.value.submit_rows_limit !== Infinity) {
this.submitLimitNotice = true
return
}
this.submit()
}
public submit() {
if (!this.selectedXLMap || !this.xlData.length) return
this.status = Status.Submitting
this.isLoading = true
this.isLoadingDesc = 'Submitting extracted data'
const filesToUpload: UploadFile[] = []
for (const file of this.uploader.queue) {
filesToUpload.push({
file: file,
fileName: file.name
})
}
const csvContent =
Object.keys(this.xlData[0]).join(',') +
'\n' +
this.xlData
.slice(0, this.licenceState.value.submit_rows_limit)
.map((row: any) => Object.values(row).join(','))
.join('\n')
const blob = new Blob([csvContent], { type: 'application/csv' })
const file: File = blobToFile(blob, this.filename + '.csv')
filesToUpload.push({
file: file,
fileName: file.name
})
const uploadUrl = 'services/editors/loadfile'
this.sasService
.uploadFile(uploadUrl, filesToUpload, {
table: this.selectedXLMap.targetDS
})
.then((res: UploadFileResponse) => {
if (res.adapterResponse.sasjsAbort) {
const abortRes = res.adapterResponse
const abortMsg = abortRes.sasjsAbort[0].MSG
const macMsg = abortRes.sasjsAbort[0].MAC
this.eventService.showAbortModal('', abortMsg, {
SYSWARNINGTEXT: abortRes.SYSWARNINGTEXT,
SYSERRORTEXT: abortRes.SYSERRORTEXT,
MAC: macMsg,
_PROGRAM: abortRes._PROGRAM
})
} 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.response)
})
.finally(() => {
this.status = Status.ReadyToSubmit
this.isLoading = false
this.isLoadingDesc = ''
})
}
public extractData(wb: XLSX.WorkBook) {
const extractedData: XLUploadEntry[] = []
this.xlmapRules.forEach((rule) => {
let sheetName = rule.XLMAP_SHEET
// if sheet name is not an absolute name rather an index string like /1, /2, etc
// we extract the index and find absolute sheet name for specified index
if (sheetName.startsWith('/')) {
const temp = sheetName.split('/')[1]
const sheetIndex = parseInt(temp) - 1
sheetName = wb.SheetNames[sheetIndex]
}
const sheet = wb.Sheets[sheetName]
const arrayOfObjects = <any[]>XLSX.utils.sheet_to_json(sheet, {
raw: true,
header: 'A',
blankrows: true
})
const start = getCellAddress(rule.XLMAP_START, arrayOfObjects)
const finish = getFinishingCell(start, rule.XLMAP_FINISH, arrayOfObjects)
const a1Range = `${start}:${finish}`
const range = XLSX.utils.decode_range(a1Range)
const rangedData = <any[]>XLSX.utils.sheet_to_json(sheet, {
raw: true,
range: a1Range,
header: 'A',
blankrows: true
})
for (let i = 0; i < rangedData.length; i++) {
const row = rangedData[i]
// `range.s.c` is the index of first column in the range
// `range.e.c` is the index of last column in the range
// 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)
if (col in row) {
// in excel's R1C1 notation indexing starts from 1 but in JS it starts from 0
// therefore, we'll have to add 1 to rows and cols
extractedData.push({
LOAD_REF: '0',
XLMAP_ID: rule.XLMAP_ID,
XLMAP_RANGE_ID: rule.XLMAP_RANGE_ID,
ROW_NO: i + 1,
COL_NO: x + 1,
VALUE_TXT: row[col]
})
}
}
}
})
this.status = Status.ReadyToSubmit
this.isLoading = false
this.isLoadingDesc = ''
this.xlData = extractedData
this.setSelectedTab(Tabs.Data)
}
async viewXLMapRules() {
if (!this.selectedXLMap) return
this.isLoading = true
this.isLoadingDesc = 'Loading excel rules'
this.status = Status.FetchingRules
await this.sasStoreService
.getXLMapRules(this.selectedXLMap.id)
.then((res) => {
this.xlmapRules = res.xlmaprules
this.status = Status.ReadyToUpload
})
.catch((err) => {
this.loggerService.error(err)
})
this.isLoading = false
this.isLoadingDesc = ''
}
private load() {
this.xlmaps = globals.xlmaps
this.xlmapsLoading = false
const id = this.route.snapshot.params['id']
if (id) {
const xlmapListItem = this.xlmaps.find((item) => item.id === id)
if (xlmapListItem) {
this.selectedXLMap = xlmapListItem
this.viewXLMapRules()
}
}
}
ngOnInit() {
this.licenceService.hot_license_key.subscribe(
(hot_license_key: string | undefined) => {
this.hotTableLicenseKey = hot_license_key
this.hotTableSettings.set(this.buildHotSettings())
}
)
}
ngAfterViewInit() {
return
}
ngAfterContentInit(): void {
if (globals.editor.startupSet) {
this.load()
} else {
this.eventService.onStartupDataLoaded.subscribe(() => {
this.load()
})
}
}
}
<app-sidebar>
@if (xlmapsLoading) {
<div class="my-10-mx-auto text-center">
<clr-spinner clrMedium></clr-spinner>
</div>
}
<clr-tree>
<clr-tree-node class="search-node">
<div class="tree-search-wrapper">
<input
appStealFocus
clrInput
#searchXLMapTreeInput
placeholder="Filter by Id"
name="input"
[(ngModel)]="searchString"
(keyup)="xlmapListOnFilter()"
autocomplete="off"
/>
@if (searchXLMapTreeInput.value.length < 1) {
<clr-icon shape="search"></clr-icon>
}
@if (searchXLMapTreeInput.value.length > 0) {
<clr-icon
(click)="searchString = ''; xlmapListOnFilter()"
shape="times"
></clr-icon>
}
</div>
</clr-tree-node>
@for (xlmap of xlmaps; track xlmap) {
<clr-tree-node>
<button
(click)="xlmapOnClick(xlmap)"
class="clr-treenode-link"
[class.active]="isActiveXLMap(xlmap.id)"
>
<clr-icon shape="file"></clr-icon>
{{ xlmap.id }}
</button>
</clr-tree-node>
}
</clr-tree>
</app-sidebar>
<div class="content-area">
@if (!selectedXLMap) {
<div class="no-table-selected">
<img
src="images/select-table.png"
class="select-table-icon"
alt="select table icon"
/>
@if (xlmaps.length > 0) {
<p class="text-center color-gray mt-10" cds-text="section">
Please select a map
</p>
}
@if (xlmaps.length < 1) {
<p class="text-center color-gray mt-10" cds-text="section">
No excel map is found
</p>
}
</div>
}
@if (isLoading) {
<div class="loadingSpinner">
<span class="spinner"> Loading... </span>
<div>
<h4>{{ isLoadingDesc }}</h4>
</div>
</div>
}
@if (!isLoading && selectedXLMap) {
<div
appDragNdrop
(fileDraggedOver)="onShowUploadModal()"
class="card h-100 d-flex clr-flex-column"
>
<clr-tabs>
<clr-tab>
<button clrTabLink (click)="selectedTab = TabsEnum.Rules">
Rules
</button>
<clr-tab-content *clrIfActive="selectedTab === TabsEnum.Rules">
</clr-tab-content>
</clr-tab>
<clr-tab>
<button clrTabLink (click)="selectedTab = TabsEnum.Data">Data</button>
<clr-tab-content *clrIfActive="selectedTab === TabsEnum.Data">
</clr-tab-content>
</clr-tab>
</clr-tabs>
<ng-container *ngTemplateOutlet="actionButtons"></ng-container>
<div class="clr-row m-0 mb-10-i viewerTitle">
<h3 class="d-flex clr-col-12 clr-justify-content-center mt-5-i">
{{ selectedXLMap.id }}
</h3>
<i class="d-flex clr-col-12 clr-justify-content-center mt-5-i">{{
selectedXLMap.description
}}</i>
<p class="d-flex clr-col-12 clr-justify-content-center mt-5-i">
Rules Source:
<a
cds-text="labelLink"
class="ml-10"
[routerLink]="'/view/data/' + rulesSource"
>
{{ rulesSource }}
</a>
</p>
<p class="d-flex clr-col-12 clr-justify-content-center mt-5-i">
Target dataset:
<a
cds-text="labelLink"
class="ml-10"
[routerLink]="'/view/data/' + selectedXLMap.targetDS"
>
{{ selectedXLMap.targetDS }}
</a>
</p>
</div>
<div class="clr-flex-1">
<hot-table
id="hot-table"
[data]="selectedTab === TabsEnum.Rules ? xlmapRules : xlData"
[settings]="hotTableSettings()"
>
</hot-table>
</div>
</div>
}
<clr-modal
appFileDrop
(fileOver)="fileOverBase($event)"
(fileDrop)="getFileDesc($event, true)"
[uploader]="uploader"
[clrModalSize]="'xl'"
[clrModalStaticBackdrop]="false"
[clrModalClosable]="true"
[(clrModalOpen)]="showUploadModal"
class="relative"
>
<h3 class="modal-title">Upload File</h3>
<div class="modal-body">
<div class="drop-area">
<span>Drop file anywhere to upload!</span>
</div>
<div class="clr-col-md-12">
<div class="clr-row card-block mt-15 d-flex justify-content-between">
<div class="clr-col-md-3 filterBtn">
<span class="filterBtn w-100">
<label
for="file-upload"
class="btn btn-sm btn-outline profile-buttons w-100"
>
Browse
</label>
</span>
<input
hidden
#fileUploadInput
id="file-upload"
type="file"
appFileSelect
[uploader]="uploader"
(change)="getFileDesc($event)"
/>
</div>
</div>
</div>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="submitLimitNotice">
<h3 class="modal-title">Notice</h3>
<div class="modal-body">
<p class="m-0">
Due to current licence, only
{{ licenceState.value.submit_rows_limit }} rows in a file will be
submitted. To remove the restriction, contact
support@datacontroller.io
</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-sm btn-primary"
(click)="submitLimitNotice = false"
>
Cancel
</button>
<button
type="button"
class="btn btn-sm btn-primary"
(click)="submit(); submitLimitNotice = false"
>
Submit
</button>
</div>
</clr-modal>
</div>
<ng-template #actionButtons>
<div class="clr-row m-0 clr-justify-content-center">
@if (status === StatusEnum.ReadyToUpload) {
<div class="d-flex clr-justify-content-center clr-col-12 clr-col-lg-4">
<button
type="button"
class="btn btn-sm btn-success btn-block mr-0"
(click)="onShowUploadModal()"
>
<clr-icon shape="upload"></clr-icon>
<span>Upload</span>
</button>
</div>
}
@if (status === StatusEnum.ReadyToSubmit) {
<div class="d-flex clr-justify-content-center clr-col-12 clr-col-lg-4">
<button
type="button"
class="btn btn-sm btn-success btn-block mr-0"
(click)="submitExcel()"
>
<clr-icon shape="upload"></clr-icon>
<span>Submit</span>
</button>
</div>
}
@if (status === StatusEnum.ReadyToSubmit) {
<div class="d-flex clr-justify-content-center clr-col-12 clr-col-lg-4">
<button
type="button"
class="btn btn-sm btn-outline-danger btn-block mr-0"
(click)="discardExtractedData()"
>
<clr-icon shape="times"></clr-icon>
<span>Discard</span>
</button>
</div>
}
</div>
</ng-template>
./xlmap.component.scss