feat(multi load): licence submit limits
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 42s
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 42s
Icons improvement, ux improvements, matched dataset link to edit table, empty table is visible on the left
This commit is contained in:
parent
18363bbbeb
commit
cffeab813d
@ -17,13 +17,13 @@ import '@cds/core/icon/register.js'
|
||||
import {
|
||||
ClarityIcons,
|
||||
exclamationTriangleIcon,
|
||||
fileIcon,
|
||||
moonIcon,
|
||||
sunIcon,
|
||||
tableIcon,
|
||||
trashIcon
|
||||
} from '@cds/core/icon'
|
||||
|
||||
ClarityIcons.addIcons(moonIcon, sunIcon, exclamationTriangleIcon, fileIcon, trashIcon)
|
||||
ClarityIcons.addIcons(moonIcon, sunIcon, exclamationTriangleIcon, tableIcon, trashIcon)
|
||||
|
||||
@Component({
|
||||
selector: 'my-app',
|
||||
|
@ -40,16 +40,11 @@
|
||||
[class.active]="dataset.active"
|
||||
>
|
||||
<cds-icon
|
||||
*ngIf="dataset.status === 'error'"
|
||||
*ngIf="!(dataset.datasource && dataset.parseResult)"
|
||||
status="danger"
|
||||
shape="exclamation-circle"
|
||||
></cds-icon>
|
||||
<cds-icon
|
||||
*ngIf="dataset.status === 'success'"
|
||||
status="success"
|
||||
shape="check-circle"
|
||||
></cds-icon>
|
||||
<cds-icon shape="file"></cds-icon>
|
||||
<cds-icon *ngIf="dataset.datasource && dataset.parseResult" shape="table"></cds-icon>
|
||||
{{ dataset.libds }}
|
||||
</button>
|
||||
</clr-tree-node>
|
||||
@ -75,7 +70,7 @@
|
||||
status="success"
|
||||
shape="check-circle"
|
||||
></cds-icon>
|
||||
<cds-icon shape="file"></cds-icon>
|
||||
<cds-icon shape="table"></cds-icon>
|
||||
{{ dataset.libds }}
|
||||
</button>
|
||||
</clr-tree-node>
|
||||
@ -114,14 +109,19 @@
|
||||
<div class="d-flex clr-justify-content-center mt-15">
|
||||
<div class="dataset-input-wrapper">
|
||||
<p cds-text="secondary regular" class="mb-20">
|
||||
Selected file: <strong>{{ selectedFile?.name }}</strong>
|
||||
<cds-icon (click)="onDiscardFile()" shape="trash" status="danger" class="ml-5 cursor-pointer"></cds-icon>
|
||||
Selected file: <strong>{{ selectedFile.name }}</strong>
|
||||
<clr-tooltip>
|
||||
<cds-icon clrTooltipTrigger (click)="onDiscardFile()" shape="trash" status="danger" class="ml-5 cursor-pointer"></cds-icon>
|
||||
<clr-tooltip-content>
|
||||
Discard the file
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</p>
|
||||
<p cds-text="secondary regular" class="mb-15">
|
||||
Paste or type the list of datasets to upload:
|
||||
</p>
|
||||
|
||||
<clr-control-helper class="mb-5">Each row is one dataset. We automatically detected some tables by the sheetname.</clr-control-helper>
|
||||
<clr-control-helper class="mb-5">Each row is one dataset. We will automatically detect tables by the sheetname and populate if any.</clr-control-helper>
|
||||
|
||||
<hot-table
|
||||
hotId="hotInstanceUserDataset"
|
||||
@ -173,17 +173,31 @@
|
||||
<div>
|
||||
<p cds-text="secondary regular" class="mb-10">
|
||||
Found in range:
|
||||
<strong
|
||||
>"{{
|
||||
activeParsedDataset.parseResult.rangeSheetRes?.sheetName
|
||||
}}"!{{
|
||||
activeParsedDataset.parseResult.rangeSheetRes?.rangeAddress
|
||||
}}</strong
|
||||
>
|
||||
|
||||
<ng-container *ngIf="activeParsedDataset.parseResult">
|
||||
<strong
|
||||
>"{{
|
||||
activeParsedDataset.parseResult.rangeSheetRes?.sheetName
|
||||
}}"!{{
|
||||
activeParsedDataset.parseResult.rangeSheetRes?.rangeAddress
|
||||
}}</strong
|
||||
>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!activeParsedDataset.parseResult">
|
||||
<strong>No data found</strong>
|
||||
</ng-container>
|
||||
</p>
|
||||
<p cds-text="secondary regular">
|
||||
Matched with dataset:
|
||||
<strong>{{ activeParsedDataset.libds }}</strong>
|
||||
<strong>
|
||||
<clr-tooltip>
|
||||
<a clrTooltipTrigger [routerLink]="'/editor/' + activeParsedDataset.libds">{{ activeParsedDataset.libds }}</a>
|
||||
<clr-tooltip-content [clrPosition]="'top-right'" [clrSize]="'sm'">
|
||||
Click to edit the table
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -194,6 +208,7 @@
|
||||
clrToggle
|
||||
[(ngModel)]="activeParsedDataset.includeInSubmission"
|
||||
name="options"
|
||||
[disabled]="!(activeParsedDataset.datasource && activeParsedDataset.parseResult)"
|
||||
required
|
||||
value="option1"
|
||||
/>
|
||||
@ -238,7 +253,14 @@
|
||||
</p>
|
||||
<p cds-text="secondary regular" class="mb-10">
|
||||
Matched with dataset:
|
||||
<strong>{{ activeSubmittedDataset.libds }}</strong>
|
||||
<strong>
|
||||
<clr-tooltip>
|
||||
<a clrTooltipTrigger [routerLink]="'/editor/' + activeSubmittedDataset.libds">{{ activeSubmittedDataset.libds }}</a>
|
||||
<clr-tooltip-content [clrPosition]="'top-right'" [clrSize]="'sm'">
|
||||
Click to edit the table
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</strong>
|
||||
</p>
|
||||
<p cds-text="secondary regular" class="mb-10">
|
||||
Status:
|
||||
@ -291,11 +313,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<clr-modal [(clrModalOpen)]="showSubmitReasonModal">
|
||||
<clr-modal [(clrModalOpen)]="showSubmitReasonModal" [clrModalClosable]="false">
|
||||
<h3 class="modal-title">
|
||||
Submit for approval {{ parsedDatasets.length }} tables
|
||||
Submit {{ tablesToSubmit.length }} {{ tablesToSubmit.length === 1 ? 'table' : 'tables' }} for approval
|
||||
</h3>
|
||||
<div class="modal-body">
|
||||
<p *ngIf="licenceState.value.submit_rows_limit !== Infinity" cds-text="body" class="licence-limit-notice mt-0 mb-15">
|
||||
Due to current licence, only
|
||||
{{ licenceState.value.submit_rows_limit }} rows in each file will
|
||||
be submitted. To remove the restriction, contact
|
||||
support@datacontroller.io.
|
||||
</p>
|
||||
|
||||
<div class="text-area-full-width">
|
||||
<label for="formFields_8" class="mb-5 d-block">Message</label>
|
||||
<textarea
|
||||
|
@ -43,4 +43,8 @@
|
||||
|
||||
.dataset-selection-actions {
|
||||
border-top: 1px solid #d3d3d3;
|
||||
}
|
||||
|
||||
.licence-limit-notice {
|
||||
color: var(--cds-alias-status-warning-dark);
|
||||
}
|
@ -27,6 +27,7 @@ import { HotTableRegisterer } from '@handsontable/angular'
|
||||
import { EditorsStageDataSASResponse } from '../models/sas/editors-stagedata.model'
|
||||
import { CellChange, ChangeSource } from 'handsontable/common'
|
||||
import { baseAfterGetColHeader } from '../shared/utils/hot.utils'
|
||||
import { ColumnSettings } from 'handsontable/settings'
|
||||
|
||||
@Component({
|
||||
selector: 'app-multi-dataset',
|
||||
@ -37,6 +38,7 @@ export class MultiDatasetComponent implements OnInit {
|
||||
@HostBinding('class.content-container') contentContainerClass = true
|
||||
|
||||
public licenceState = this.licenceService.licenceState
|
||||
public Infinity = Infinity
|
||||
|
||||
public hotTableLicenseKey: string | undefined = undefined
|
||||
public hotTableMaxRows =
|
||||
@ -83,6 +85,18 @@ export class MultiDatasetComponent implements OnInit {
|
||||
['', ''],
|
||||
['', '']
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
type: 'autocomplete',
|
||||
filter: false,
|
||||
source: []
|
||||
},
|
||||
{
|
||||
type: 'autocomplete',
|
||||
filter: false,
|
||||
source: []
|
||||
}
|
||||
],
|
||||
width: '100%',
|
||||
height: '305px',
|
||||
className: ['htDark'],
|
||||
@ -133,6 +147,12 @@ export class MultiDatasetComponent implements OnInit {
|
||||
|
||||
public getFromGlobals() {
|
||||
this.libsAndTables = globals.editor.libsAndTables
|
||||
|
||||
const libs: string[] = Object.keys(this.libsAndTables)
|
||||
|
||||
if (this.hotUserDatasets?.columns) {
|
||||
(this.hotUserDatasets.columns as ColumnSettings[])[0].source = libs;
|
||||
}
|
||||
}
|
||||
|
||||
onFileChange(event: any) {
|
||||
@ -241,13 +261,23 @@ export class MultiDatasetComponent implements OnInit {
|
||||
})
|
||||
.catch((error: string) => {
|
||||
console.warn('Parsing excel file error.', error)
|
||||
|
||||
this.parsedDatasets.push({
|
||||
libds: datasetObject.libds,
|
||||
includeInSubmission: false,
|
||||
datasetInfo: datasetObject
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onSubmitAll() {
|
||||
this.showSubmitReasonModal = true
|
||||
if (this.tablesToSubmit.length) {
|
||||
this.showSubmitReasonModal = true
|
||||
} else {
|
||||
this.eventService.showInfoModal('No tables to submit', 'Please include at least one table to proceed.')
|
||||
}
|
||||
}
|
||||
|
||||
onDiscard() {
|
||||
@ -264,7 +294,7 @@ export class MultiDatasetComponent implements OnInit {
|
||||
|
||||
if (this.activeParsedDataset) {
|
||||
this.hotInstance.updateSettings({
|
||||
data: this.activeParsedDataset.datasource,
|
||||
data: this.activeParsedDataset.datasource || [],
|
||||
colHeaders: this.activeParsedDataset.datasetInfo.headerColumns,
|
||||
columns: this.activeParsedDataset.datasetInfo.dcValidator?.getRules(),
|
||||
readOnly: true,
|
||||
@ -301,6 +331,8 @@ export class MultiDatasetComponent implements OnInit {
|
||||
this.markUnmatchedRows(row)
|
||||
}
|
||||
|
||||
this.dynamicCellValidations()
|
||||
|
||||
this.hotInstanceUserDataset.render()
|
||||
}
|
||||
})
|
||||
@ -315,6 +347,19 @@ export class MultiDatasetComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
dynamicCellValidations() {
|
||||
const hotData = this.hotInstanceUserDataset.getData()
|
||||
|
||||
hotData.forEach((row, rowIndex) => {
|
||||
const library = row[0]
|
||||
|
||||
if (library && library.length) {
|
||||
const tables = this.libsAndTables[library]
|
||||
this.hotInstanceUserDataset.setCellMeta(rowIndex, 1, 'source', tables)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
markUnmatchedRows(row: number) {
|
||||
const dataAtRow = this.hotInstanceUserDataset.getDataAtRow(row) as number[]
|
||||
const dataset = `${dataAtRow[0]}.${dataAtRow[1]}`
|
||||
@ -381,14 +426,16 @@ export class MultiDatasetComponent implements OnInit {
|
||||
this.userInputDatasets = ''
|
||||
|
||||
sheetNames.forEach((sheetName: string, index: number) => {
|
||||
const trimmedSheetname = sheetName.trim()
|
||||
|
||||
if (
|
||||
this.isValidDatasetFormat(sheetName) &&
|
||||
this.isValidDatasetReference(sheetName)
|
||||
this.isValidDatasetFormat(trimmedSheetname) &&
|
||||
this.isValidDatasetReference(trimmedSheetname)
|
||||
) {
|
||||
this.matchedDatasets.push(sheetName)
|
||||
this.matchedDatasets.push(trimmedSheetname)
|
||||
} else {
|
||||
console.warn(
|
||||
`Sheet name: ${sheetName} is not an actual dataset reference.`
|
||||
`Sheet name: ${trimmedSheetname} is not an actual dataset reference.`
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -417,6 +464,7 @@ export class MultiDatasetComponent implements OnInit {
|
||||
}
|
||||
|
||||
this.hotInstanceUserDataset.updateData(hotReadyData)
|
||||
this.dynamicCellValidations()
|
||||
}
|
||||
|
||||
onParsedDatasetClick(parsedDataset: ParsedDataset) {
|
||||
@ -460,6 +508,10 @@ export class MultiDatasetComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public get tablesToSubmit(): ParsedDataset[] {
|
||||
return this.parsedDatasets.filter(dataset => dataset.datasource && dataset.parseResult && dataset.includeInSubmission)
|
||||
}
|
||||
|
||||
public downloadFile(
|
||||
response: any
|
||||
) {
|
||||
@ -508,6 +560,8 @@ export class MultiDatasetComponent implements OnInit {
|
||||
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
|
||||
// Skip the table if toggle switch is off
|
||||
if (!table.includeInSubmission) continue
|
||||
// Skip the table if datasets is present and this table not defined in it
|
||||
@ -544,15 +598,13 @@ export class MultiDatasetComponent implements OnInit {
|
||||
this.licenceState.value.submit_rows_limit
|
||||
)
|
||||
|
||||
console.log('submitData', submitData)
|
||||
|
||||
let error
|
||||
let success
|
||||
|
||||
await this.sasStoreService
|
||||
.updateTable(
|
||||
updateParams,
|
||||
table.datasource,
|
||||
submitData,
|
||||
'SASControlTable',
|
||||
'editors/stagedata',
|
||||
table.datasetInfo.data.$sasdata,
|
||||
@ -579,7 +631,7 @@ export class MultiDatasetComponent implements OnInit {
|
||||
if (explicitDatasets) {
|
||||
const existingResultIndex = requestsResults.findIndex(result => result.libds === table.libds)
|
||||
|
||||
if (existingResultIndex) {
|
||||
if (existingResultIndex > -1) {
|
||||
requestsResults[existingResultIndex] = requestResult
|
||||
} else {
|
||||
requestsResults.push(requestResult)
|
||||
@ -598,7 +650,11 @@ export class MultiDatasetComponent implements OnInit {
|
||||
|
||||
async reSubmitTable(activeSubmittedDataset: SubmittedDatasetResult) {
|
||||
// Submit only particular table
|
||||
this.submitTables([activeSubmittedDataset.libds])
|
||||
await this.submitTables([activeSubmittedDataset.libds])
|
||||
|
||||
// Activate new resubmitted table
|
||||
const newSubmittedDataset = this.submittedDatasets.find(sd => sd.libds === activeSubmittedDataset.libds)
|
||||
if (newSubmittedDataset) newSubmittedDataset.active = true
|
||||
}
|
||||
|
||||
/**
|
||||
@ -799,9 +855,9 @@ export interface DatasetsObject extends EditorsGetDataServiceResponse {
|
||||
|
||||
export interface ParsedDataset {
|
||||
libds: string
|
||||
parseResult: ParseResult
|
||||
parseResult?: ParseResult
|
||||
datasetInfo: DatasetsObject
|
||||
datasource: any[]
|
||||
datasource?: any[]
|
||||
includeInSubmission: boolean
|
||||
status?: 'success' | 'error'
|
||||
active?: boolean
|
||||
|
Loading…
Reference in New Issue
Block a user