Files
dc/client/src/app/editor/editor.component.html
Mihajlo Medjedovic eb7c44333c
Some checks failed
Build / Build-and-ng-test (pull_request) Failing after 52s
feat(multi load): refactored range find function, unlocking excel with password is reusable
2024-06-13 12:59:26 +02:00

876 lines
28 KiB
HTML

<div class="content-area d-flex clr-flex-column">
<clr-modal
appFileDrop
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
(fileDrop)="attachFile($event, true)"
[clrModalSize]="'xl'"
[clrModalStaticBackdrop]="false"
[clrModalClosable]="excelUploadState === 'Validating-DQ'"
[(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="card-header"
style="display: flex; flex-direction: column; justify-content: center"
>
<div
ng2FileDrop
*ngIf="!excelFileParsing"
[class.nv-file-over]="hasBaseDropZoneOver"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="well my-drop-zone"
(onFileDrop)="getFileDesc($event, true)"
>
<p class="file-drop-text">Drop File Here !</p>
</div>
</div> -->
<div class="clr-row card-block mt-15 d-flex justify-content-between">
<div class="clr-col-md-auto">
<div class="encoding-block">
<clr-radio-container class="mt-0-i" clrInline>
<clr-radio-wrapper>
<input
type="radio"
clrRadio
value="UTF-8"
name="encoding"
[(ngModel)]="encoding"
[disabled]="filename != ''"
/>
<label>UTF-8</label>
</clr-radio-wrapper>
<clr-radio-wrapper>
<input
type="radio"
clrRadio
value="WLATIN1"
name="encoding"
[(ngModel)]="encoding"
[disabled]="filename != ''"
/>
<label>WLATIN1</label>
</clr-radio-wrapper>
</clr-radio-container>
</div>
</div>
<div
*ngIf="!excelFileParsing && !uploadLoading"
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)="attachFile($event)"
/>
</div>
<div
*ngIf="!excelFileParsing && !uploadLoading"
class="clr-col-md-3 editBtn"
>
<button
[disabled]="true"
class="btnView btn btn-sm btn-success profile-buttons w-100"
(click)="uploadParsedFiles()"
>
Upload
</button>
</div>
<div class="clr-col-md-auto">
<button
*ngIf="excelUploadState !== 'Validating'"
type="button"
class="btn btn-primary mr-0"
(click)="showUploadModal = false"
[disabled]="excelFileParsing || uploadLoading"
>
Close
</button>
<button
*ngIf="excelUploadState === 'Validating-DQ'"
type="button"
class="btn btn-primary mr-0"
(click)="showUploadModal = false"
>
Skip
</button>
</div>
<div *ngIf="excelFileParsing" class="excel-parsing clr-col-md-12">
<app-upload-stater #uploadStater></app-upload-stater>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<!-- <button type="button" class="btn btn-outline" (click)="showUploadModal = false">Cancel</button> -->
<!-- <button type="button" class="btn btn-primary" (click)="showUploadModal = false">Close</button> -->
</div>
</clr-modal>
<app-edit-record
*ngIf="currentEditRecordIndex > -1"
[currentRecord]="currentEditRecord"
[recordAction]="recordAction"
[libds]="libds"
[queryFilter]="queryFilter"
[filter]="filter"
[submitLoading]="submitLoading"
[headerPks]="headerPks"
[cellValidation]="cellValidation"
[currentRecordIndex]="currentEditRecordIndex"
[currentRecordLoadings]="currentEditRecordLoadings"
[currentRecordErrors]="currentEditRecordErrors"
[currentRecordValidator]="currentEditRecordValidator"
(onRecordChange)="confirmRecordEdit()"
(onRecordInputFocused)="onRecordInputFocus($event)"
(onRecordEditClose)="closeRecordEdit()"
(onNextRecord)="onNextRecord()"
(onPreviousRecord)="onPreviousRecord()"
></app-edit-record>
<div #ht class="clr-flex-1">
<div *ngIf="!validationDone && submit" class="progresStatic progress loop">
<progress></progress>
</div>
<div
appDragNdrop
(fileDraggedOver)="onShowUploadModal()"
class="card border-0 box-shadow-none-i position-relative h-100 d-flex clr-flex-column background-transparent"
>
<div
class="card-header clr-row buttonBar headerBar clr-flex-md-row clr-justify-content-center clr-justify-content-lg-end"
>
<div
*ngIf="tableTrue"
class="clr-col-12 clr-col-md-3 clr-col-lg-4 backBtn"
>
<span
class="btn icon-collapse btn-sm btn-icon btn-dimmed"
[routerLink]="['/home']"
>
<clr-icon shape="caret" dir="left" size="20"></clr-icon>
<span class="text">Back to table selection</span>
</span>
<span
(click)="viewboxManager()"
class="btn icon-collapse btn-sm btn-icon btn-dimmed viewbox-open"
>
<clr-icon shape="view-cards" size="20"></clr-icon>
<span class="text">Viewboxes</span>
</span>
</div>
<div
class="clr-col-12 clr-col-md-5 clr-col-lg-4 d-flex flex-column align-items-center"
[class.clr-col-lg-12]="!tableTrue"
>
<h4
*ngVar="{
libName: (libds?.split('.'))![0],
tableName: (libds?.split('.'))![1]
} as libdsParsed"
class="editor-title text-center mt-0-i"
>
<clr-tooltip>
<clr-icon
clrTooltipTrigger
(click)="datasetInfo = true"
shape="info-circle"
class="is-highlight cursor-pointer"
size="24"
></clr-icon>
<clr-icon
*ngIf="libdsParsed.tableName.includes('-FC')"
shape="bolt"
class="color-yellow"
></clr-icon>
<span clrTooltipTrigger>
{{ libdsParsed.libName }}.<a
class="mr-10 view-table"
[routerLink]="'/view/data/' + libds!"
>{{ libdsParsed.tableName.replace('-FC', '') }}</a
>
</span>
<ng-container *ngIf="this.dsNote && this.dsNote.length > 0">
<clr-tooltip-content
clrPosition="bottom-left"
clrSize="lg"
*clrIfOpen
>
{{ this.dsNote }}
</clr-tooltip-content>
</ng-container>
</clr-tooltip>
<ng-container *ngIf="dataSource">
<ng-container *ngIf="!zeroFilterRows">
({{ dataSource.length | thousandSeparator: ',' }}
{{ dataSource.length === 1 ? 'row' : 'rows' }}, {{ cols.length
}}{{ cols.length === 1 ? ' col' : ' cols' }})
</ng-container>
<ng-container *ngIf="zeroFilterRows"> (0 rows) </ng-container>
</ng-container>
</h4>
</div>
<div
*ngIf="tableTrue"
class="clr-col-12 clr-col-md-4 clr-col-lg-4 btnCtrl"
>
<ng-container *ngIf="hotTable.readOnly && !uploadPreview">
<button
type="button"
class="btnView btn icon-collapse btn-sm btn-icon btn-block btn-dimmed"
(click)="openQb()"
>
<clr-icon shape="filter"></clr-icon>
<span class="text">Filter</span>
</button>
<button
type="button"
class="btn icon-collapse btn-sm btn-primary btn-block"
(click)="editTable()"
>
<clr-icon shape="note"></clr-icon>
<span class="text">Edit</span>
</button>
<button
*ngIf="!columnLevelSecurityFlag"
(click)="onShowUploadModal()"
type="button"
class="btn icon-collapse btn-sm btn-success btn-block mr-0"
>
<clr-icon shape="upload"></clr-icon>
<span class="text">Upload</span>
</button>
</ng-container>
<ng-container *ngIf="!hotTable.readOnly && !uploadPreview">
<button
type="button"
class="btn btn-sm btn-icon btn-outline-danger"
(click)="cancelEdit()"
>
<clr-icon shape="times"></clr-icon>
<span>Cancel</span>
</button>
<clr-tooltip>
<button
clrTooltipTrigger
type="button"
class="btn btn-sm btn-success"
[clrLoading]="addingNewRow"
[class.dc-locked-control]="restrictions.restrictAddRow"
(click)="!restrictions.restrictAddRow ? addRow() : ''"
>
<clr-icon shape="plus" size="16"></clr-icon>Add Row
</button>
<clr-tooltip-content
clrPosition="bottom-left"
clrSize="lg"
*clrIfOpen
>
<span *ngIf="restrictions.restrictAddRow"
>To unlock more than
{{ licenceState.value.editor_rows_allowed }}
{{
licenceState.value.editor_rows_allowed === 1
? 'row'
: 'rows'
}}, contact support&#64;datacontroller.io</span
>
</clr-tooltip-content>
</clr-tooltip>
<button
type="button"
class="btn btn-sm btn-primary"
(click)="checkSave()"
>
<clr-icon shape="check" size="20"></clr-icon>Submit
</button>
</ng-container>
<ng-container *ngIf="uploadPreview">
<button
type="button"
class="btn btn-sm btn-icon btn-outline-danger btn-upload-preview"
(click)="discardSourceFile = true"
>
<clr-icon shape="times"></clr-icon>
<span>Discard file</span>
</button>
<button
*ngIf="hotTable.readOnly"
type="button"
class="btn btn-sm btn-primary btn-upload-preview"
(click)="manualFileEditModal = true"
>
<clr-icon shape="note"></clr-icon>
<span>Edit</span>
</button>
<button
type="button"
class="btn btn-sm btn-success preview-submit"
(click)="submitExcel()"
[clrLoading]="uploadLoading"
>
<clr-icon shape="check" size="20"></clr-icon>
Submit
</button>
</ng-container>
</div>
<div
*ngIf="!['', ' '].includes(queryText)"
class="clr-col-md-12 infoBar"
>
<span
>FILTER :
<b>{{ queryText }}</b>
</span>
</div>
</div>
<div
class="card-block p-0 clr-flex-1 background-transparent"
[ngClass]="{ headerBarFilter: !['', ' '].includes(queryText) }"
>
<div *ngIf="!tableTrue" class="card-text">
<div
class="h-70vh d-flex justify-content-center flex-column align-items-center"
>
<ng-container *ngIf="!getdataError">
<span class="spinner"> Loading... </span>
<div class="mt-10">
<p cds-text="section">Loading table</p>
</div>
</ng-container>
<ng-container *ngIf="getdataError">
<span>
<clr-icon shape="error-standard" class="error-icon"></clr-icon>
</span>
<div class="mt-10">
<p cds-text="section">Loading table error</p>
</div>
</ng-container>
</div>
</div>
<div
class="card-text hotEditor h-100 d-flex clr-flex-column background-transparent"
>
<!-- <div *ngIf="generateEditRecordUrlLoading" class="edit-record-spinner">
<span class="spinner">
Loading...
</span>
</div> -->
<!--{{ submit }}-->
<!--<hr>-->
<!--{{ validationDone }}-->
<div class="hot-wrapper clr-flex-1">
<hot-table
#hotInstance
hotId="hotInstance"
id="hotTable"
class="edit-hot"
className="htDark"
[class.hidden]="hotTable.hidden"
[licenseKey]="hotTable.licenseKey"
>
</hot-table>
</div>
<div>
<clr-tooltip
*ngIf="tableTrue && !restrictions.removeAddRecordButton"
>
<button
clrTooltipTrigger
type="button"
class="btn btn-sm btn-success mt-5-i"
[class.dc-locked-control]="restrictions.restrictAddRow"
(click)="
!restrictions.restrictAddRow ? addRecordButtonClick() : ''
"
>
<clr-icon shape="plus" size="16"></clr-icon>
Add Record
</button>
<clr-tooltip-content
clrPosition="top-right"
clrSize="lg"
*clrIfOpen
>
<span *ngIf="restrictions.restrictAddRow"
>To unlock more than
{{ licenceState.value.editor_rows_allowed }}
{{
licenceState.value.editor_rows_allowed === 1
? 'row'
: 'rows'
}}, contact support&#64;datacontroller.io</span
>
</clr-tooltip-content>
</clr-tooltip>
<p
*ngIf="
licenceState.value.editor_rows_allowed !== Infinity &&
dataSource &&
dataSource.length > licenceState.value.editor_rows_allowed
"
class="mt-2-i w-100 text-center"
>
To display more than
{{ licenceState.value.editor_rows_allowed }} rows, contact
<contact-link />
</p>
</div>
<!--<hr>
<hot-table hotId="hotInstance" id="hotTable">
</hot-table>-->
<div class="modal" *ngIf="submit">
<!-- && validationDone should be in constraint, but validation is not correct on front end so it is comment -->
<!-- TODO: fix validation in line above -->
<div class="modal-dialog modal-lg" role="dialog" aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
<button aria-label="Close" class="close" type="button">
<clr-icon aria-hidden="true" shape="close"></clr-icon>
</button>
<h3 class="modal-title">
Submit for Approval ({{ rowsChanged.rowsAdded }} added,
{{ rowsChanged.rowsUpdated }} updated,
{{ rowsChanged.rowsDeleted }} deleted)
</h3>
</div>
<div class="modal-body">
<span
*ngIf="
totalRowsChanged > licenceState.value.submit_rows_limit &&
licenceState.value.submit_rows_limit !== Infinity
"
class="d-block w-100 text-center color-red"
>Only
{{ licenceState.value.submit_rows_limit }}
{{
licenceState.value.submit_rows_limit === 1
? 'row'
: 'rows'
}}
will be submitted. To remove the restriction, contact
support&#64;datacontroller.io</span
>
<div *ngIf="tableTrue" class="clr-offset-md-2 clr-col-md-8">
<div class="text-area-full-width">
<label for="formFields_8" class="mb-5 d-block"
>Message</label
>
<textarea
clrTextarea
[(ngModel)]="message"
[disabled]="!validationDone"
tabindex="0"
[value]="
!validationDone
? 'Please wait while we validate ' +
cols.length * modifedRowsIndexes.length +
' cells.'
: ''
"
class="submit-reason"
type="text"
id="formFields_8"
></textarea>
</div>
<!-- TODO:approvers list -->
<!-- <div>
<div class="col-md-12" style="max-height: 150px;overflow: auto;">
<ul class="list">
<li *ngFor="let approve of approvers">{{approve}}</li>
</ul>
</div>
</div> -->
</div>
</div>
<div class="modal-footer justify-content-center-i">
<button
id="submitBtn"
[disabled]="!validationDone"
type="submit"
class="btn btn-sm btn-success-outline m-0"
tabindex="0"
(click)="saveTable(hotTable.data)"
>
Submit
</button>
<button
id="cancelSubmitBtn"
type="button"
class="btn btn-sm btn-outline"
tabindex="0"
(click)="cancelSubmit(); submit = false; validationDone = 0"
>
Cancel
</button>
</div>
</div>
</div>
</div>
<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&#64;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)="uploadParsedFiles(); submitLimitNotice = false"
>
Submit
</button>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="badEdit">
<h3 class="modal-title">{{ badEditTitle || 'Error' }}</h3>
<div class="modal-body">
<p>{{ badEditCause }}</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-sm btn-primary"
(click)="badEdit = false"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="pkNull">
<h3 class="modal-title">Error</h3>
<div class="modal-body">
<p>
Null values or incorrect data types cannot be submitted for
Primary Key columns
</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-primary"
(click)="pkNull = false; badEdit = false"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="noPkNull">
<h3 class="modal-title">Error</h3>
<div class="modal-body">
<p>Incorrect data types in non-Primary Key columns</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-primary"
(click)="noPkNull = false; badEdit = false"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal class="duplicate-keys-modal" [(clrModalOpen)]="pkDups">
<h3 class="modal-title">Error</h3>
<div class="modal-body">
<p>
Duplicate values cannot be submitted for Primary Key columns
</p>
<p>Duplicates found:</p>
<span
class="d-block"
*ngFor="
let duplicatePkIndex of duplicatePkIndexes;
let i = index
"
>
On row {{ duplicatePkIndex + 1 }}:
{{
pkFields[duplicatePkIndex].replace('|', '') | pkSpaceSeparate
}}
</span>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-primary"
(click)="pkDups = false"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="tooLong">
<h3 class="modal-title">Error</h3>
<div class="modal-body">
<p>
The following columns have values that exceed length limits:
</p>
<p *ngFor="let cell of exceedCells">
{{ cell.col }}({{ cell.len }}), {{ cell.val }}
</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-primary"
(click)="tooLong = false; cleanExceed()"
>
Ok
</button>
</div>
</clr-modal>
</div>
</div>
<!-- <div class="card-footer" style="display:flex; justify-content: center;">
</div> -->
</div>
</div>
</div>
<div class="modal z-index-highest" *ngIf="nullVariables">
<div class="modal-dialog" role="dialog" aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
<button aria-label="Close" class="close" type="button">
<clr-icon aria-hidden="true" shape="close"></clr-icon>
</button>
<h3 class="modal-title">Error</h3>
</div>
<div class="modal-body">
<p>You cannot submit empty clauses</p>
</div>
<div class="modal-footer">
<button
class="btn btn-sm btn-primary"
(click)="nullVariables = false"
type="button"
>
Ok
</button>
</div>
</div>
</div>
</div>
<clr-modal
[(clrModalOpen)]="filter"
[clrModalSize]="'xl'"
[clrModalClosable]="false"
class="filter-modal"
>
<h3 class="modal-title center text-center color-darker-gray">
Filter for table:
<span> {{ libds }} </span>
</h3>
<div class="modal-body">
<app-query #queryFilter *ngIf="filter"></app-query>
</div>
<div class="modal-footer">
<button (click)="resetFilter()" type="button" class="btn btn-sm btn-link">
reset filter
</button>
<button
type="button"
class="btn btn-sm btn-outline"
(click)="filter = false"
>
Cancel
</button>
<button
[clrLoading]="submitLoading"
type="button"
class="btn btn-sm btn-success-outline"
(click)="sendClause()"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="queryErr">
<h3 class="modal-title">Error</h3>
<div class="modal-body">
<p>{{ queryErrMessage }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="queryErr = false">
Cancel
</button>
<button type="button" class="btn btn-primary" (click)="queryErr = false">
Ok
</button>
</div>
</clr-modal>
<clr-modal
[(clrModalOpen)]="discardSourceFile"
[clrModalSize]="'xl'"
[clrModalClosable]="false"
>
<h3 class="modal-title center text-center color-darker-gray">Warning</h3>
<div class="modal-body">
This action will discard the source file and it's loaded data
<b>{{ filename }}</b> Do you wish to proceed?
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-sm btn-outline"
(click)="discardSourceFile = false"
>
Cancel
</button>
<button
type="button"
class="btn btn-sm btn-success-outline"
(click)="discardSourceFile = false; discardPendingExcel(true)"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal
[(clrModalOpen)]="filePasswordModal"
[clrModalSize]="'md'"
[clrModalClosable]="false"
>
<h3 class="modal-title center text-center color-darker-gray">
Password Protected File
</h3>
<div class="modal-body d-flex clr-justify-content-center">
<p class="m-0">Please enter password:</p>
<input
#filePasswordInput
data-lpignore="true"
autocomplete="off"
id="filePasswordInput"
type="text"
class="clr-input disable-password-manager"
/>
</div>
<div class="modal-footer">
<p *ngIf="fileUnlockError" class="m-0 color-red">
Sorry that didn't work, try again.
</p>
<button
type="button"
class="btn btn-sm btn-outline"
(click)="filePasswordModal = false; filePasswordSubject.next(undefined)"
>
Cancel upload
</button>
<button
type="button"
class="btn btn-sm btn-success-outline"
[disabled]="filePasswordInput.value.length < 1"
(click)="
filePasswordModal = false;
filePasswordSubject.next(filePasswordInput.value)
"
>
Unlock
</button>
</div>
</clr-modal>
<clr-modal
[(clrModalOpen)]="manualFileEditModal"
[clrModalSize]="'xl'"
[clrModalClosable]="false"
>
<h3 class="modal-title center text-center color-darker-gray">Warning</h3>
<div class="modal-body">
Manually editing this data will mean the source file
<b>{{ filename }}</b> will be discarded. Do you wish to proceed?
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-sm btn-outline"
(click)="manualFileEditModal = false"
>
Cancel
</button>
<button
type="button"
class="btn btn-sm btn-success-outline"
(click)="manualFileEditModal = false; previewTableEditConfirm()"
>
Ok
</button>
</div>
</clr-modal>
<app-dataset-info
[(open)]="datasetInfo"
[dsmeta]="dsmeta"
[versions]="versions"
(rowClicked)="datasetInfoModalRowClicked($event)"
>
</app-dataset-info>
<app-viewboxes [(viewboxModal)]="viewboxes"></app-viewboxes>