Bumps @angular/* to 21 (passing through 20 as a transient step, since vendored Clarity has no Angular-20-compatible release) and @typescript-eslint to 8.65.0 for TS 5.9 compat. Applies the required ng update migrations, including *ngIf/*ngFor/*ngSwitch -> control-flow syntax across 37 templates.
979 lines
32 KiB
HTML
979 lines
32 KiB
HTML
<main 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" 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>
|
|
@if (!excelFileParsing && !uploadLoading) {
|
|
<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)="attachFile($event)"
|
|
/>
|
|
</div>
|
|
}
|
|
|
|
@if (!excelFileParsing && !uploadLoading) {
|
|
<div 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">
|
|
@if (excelUploadState !== 'Validating') {
|
|
<button
|
|
type="button"
|
|
class="btn btn-primary mr-0"
|
|
(click)="showUploadModal = false"
|
|
[disabled]="excelFileParsing || uploadLoading"
|
|
>
|
|
Close
|
|
</button>
|
|
}
|
|
@if (excelUploadState === 'Validating-DQ') {
|
|
<button
|
|
type="button"
|
|
class="btn btn-primary mr-0"
|
|
(click)="showUploadModal = false"
|
|
>
|
|
Skip
|
|
</button>
|
|
}
|
|
</div>
|
|
|
|
@if (excelFileParsing) {
|
|
<div 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>
|
|
|
|
@if (currentEditRecordIndex > -1) {
|
|
<app-edit-record
|
|
[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">
|
|
@if (!validationDone && submit) {
|
|
<div 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"
|
|
>
|
|
@if (tableTrue && !embed) {
|
|
<div 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
|
|
aria-hidden="true"
|
|
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
|
|
aria-hidden="true"
|
|
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"
|
|
>
|
|
<clr-tooltip>
|
|
<clr-icon
|
|
clrTooltipTrigger
|
|
(click)="datasetInfo = true"
|
|
shape="info-circle"
|
|
aria-label="View dataset meta info"
|
|
class="is-highlight cursor-pointer"
|
|
size="24"
|
|
></clr-icon>
|
|
|
|
@if (libdsParsed.tableName.includes('-FC')) {
|
|
<clr-icon
|
|
aria-hidden="true"
|
|
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>
|
|
|
|
@if (this.dsNote && this.dsNote.length > 0) {
|
|
<clr-tooltip-content
|
|
clrPosition="bottom-left"
|
|
clrSize="lg"
|
|
*clrIfOpen
|
|
>
|
|
{{ this.dsNote }}
|
|
</clr-tooltip-content>
|
|
}
|
|
</clr-tooltip>
|
|
|
|
@if (dataSource) {
|
|
@if (!zeroFilterRows) {
|
|
({{ dataSource.length | thousandSeparator: ',' }}
|
|
{{ dataSource.length === 1 ? 'row' : 'rows' }}, {{ cols.length
|
|
}}{{ cols.length === 1 ? ' col' : ' cols' }})
|
|
}
|
|
@if (zeroFilterRows) {
|
|
(0 rows)
|
|
}
|
|
}
|
|
</h4>
|
|
</div>
|
|
@if (tableTrue) {
|
|
<div class="clr-col-12 clr-col-md-4 clr-col-lg-4 btnCtrl">
|
|
@if (hotTable.readOnly && !uploadPreview) {
|
|
@if (!isVaEmbed) {
|
|
<button
|
|
type="button"
|
|
class="btnView btn icon-collapse btn-sm btn-icon btn-block btn-dimmed"
|
|
(click)="openQb()"
|
|
>
|
|
<clr-icon aria-hidden="true" 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 aria-hidden="true" shape="note"></clr-icon>
|
|
<span class="text">Edit</span>
|
|
</button>
|
|
@if (!columnLevelSecurityFlag) {
|
|
<button
|
|
(click)="onShowUploadModal()"
|
|
type="button"
|
|
class="btn icon-collapse btn-sm btn-success btn-block mr-0"
|
|
>
|
|
<clr-icon aria-hidden="true" shape="upload"></clr-icon>
|
|
<span class="text">Upload</span>
|
|
</button>
|
|
}
|
|
}
|
|
@if (!hotTable.readOnly && !uploadPreview) {
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-icon btn-outline-danger"
|
|
(click)="cancelEdit()"
|
|
>
|
|
<clr-icon aria-hidden="true" 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 aria-hidden="true" shape="plus" size="16"></clr-icon
|
|
>Add Row
|
|
</button>
|
|
<clr-tooltip-content
|
|
clrPosition="bottom-left"
|
|
clrSize="lg"
|
|
*clrIfOpen
|
|
>
|
|
@if (restrictions.restrictAddRow) {
|
|
<span
|
|
>To unlock more than
|
|
{{ licenceState.value.editor_rows_allowed }}
|
|
{{
|
|
licenceState.value.editor_rows_allowed === 1
|
|
? 'row'
|
|
: 'rows'
|
|
}}, contact support@datacontroller.io</span
|
|
>
|
|
}
|
|
</clr-tooltip-content>
|
|
</clr-tooltip>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-primary"
|
|
(click)="checkSave()"
|
|
>
|
|
<clr-icon aria-hidden="true" shape="check" size="20"></clr-icon
|
|
>Submit
|
|
</button>
|
|
}
|
|
@if (uploadPreview) {
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-icon btn-outline-danger btn-upload-preview"
|
|
(click)="discardSourceFile = true"
|
|
>
|
|
<clr-icon aria-hidden="true" shape="times"></clr-icon>
|
|
<span>Discard file</span>
|
|
</button>
|
|
@if (hotTable.readOnly) {
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-primary btn-upload-preview"
|
|
(click)="manualFileEditModal = true"
|
|
>
|
|
<clr-icon aria-hidden="true" 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 aria-hidden="true" shape="check" size="20"></clr-icon>
|
|
Submit
|
|
</button>
|
|
}
|
|
</div>
|
|
}
|
|
@if (!['', ' '].includes(queryText)) {
|
|
<div 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) }"
|
|
>
|
|
@if (!tableTrue) {
|
|
<div class="card-text">
|
|
<div
|
|
class="h-70vh d-flex justify-content-center flex-column align-items-center"
|
|
>
|
|
@if (!getdataError) {
|
|
<span class="spinner"> Loading... </span>
|
|
<div class="mt-10">
|
|
<p cds-text="section">Loading table</p>
|
|
</div>
|
|
}
|
|
@if (getdataError) {
|
|
<span>
|
|
<clr-icon
|
|
aria-hidden="true"
|
|
shape="error-standard"
|
|
class="error-icon"
|
|
></clr-icon>
|
|
</span>
|
|
<div class="mt-10">
|
|
<p cds-text="section">Loading table error</p>
|
|
</div>
|
|
}
|
|
</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
|
|
id="hotTable"
|
|
class="edit-hot"
|
|
[class.hidden]="hotTable.hidden"
|
|
[data]="hotTable.data"
|
|
[settings]="hotTableSettings"
|
|
>
|
|
</hot-table>
|
|
</div>
|
|
|
|
<div>
|
|
@if (
|
|
tableTrue && !restrictions.removeAddRecordButton && !isVaEmbed
|
|
) {
|
|
<clr-tooltip>
|
|
<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
|
|
aria-hidden="true"
|
|
shape="plus"
|
|
size="16"
|
|
></clr-icon>
|
|
Add Record
|
|
</button>
|
|
<clr-tooltip-content
|
|
clrPosition="top-right"
|
|
clrSize="lg"
|
|
*clrIfOpen
|
|
>
|
|
@if (restrictions.restrictAddRow) {
|
|
<span
|
|
>To unlock more than
|
|
{{ licenceState.value.editor_rows_allowed }}
|
|
{{
|
|
licenceState.value.editor_rows_allowed === 1
|
|
? 'row'
|
|
: 'rows'
|
|
}}, contact support@datacontroller.io</span
|
|
>
|
|
}
|
|
</clr-tooltip-content>
|
|
</clr-tooltip>
|
|
}
|
|
|
|
<!-- VA data-driven content mode: filter controls only. Edit/Submit
|
|
use the normal top toolbar (same as embed=true). VA opens
|
|
read-only and filters live with the report; filtering
|
|
repopulates the grid, so it is held while editing (change shown
|
|
pending) and resumes on return to read-only. -->
|
|
@if (isVaEmbed) {
|
|
<div class="va-filter-controls w-100 mt-2-i">
|
|
<!-- Read-only: auto-apply toggle + manual Apply (confirm mode).
|
|
Hidden while editing (filtering is held). -->
|
|
@if (hotTable.readOnly) {
|
|
<label class="va-toggle">
|
|
<input
|
|
type="checkbox"
|
|
[checked]="vaAutoApply"
|
|
(change)="toggleVaAutoApply()"
|
|
/>
|
|
Auto-apply VA filters
|
|
</label>
|
|
@if (!vaAutoApply) {
|
|
<button
|
|
[disabled]="
|
|
vaFilterStatus !== 'pending' &&
|
|
vaFilterStatus !== 'loading'
|
|
"
|
|
type="button"
|
|
class="btn btn-sm btn-primary"
|
|
(click)="applyPendingVaFilter()"
|
|
>
|
|
Apply filter
|
|
</button>
|
|
}
|
|
}
|
|
<!-- Edit mode: filtering is held so edits aren't wiped. -->
|
|
@if (!hotTable.readOnly) {
|
|
<span class="va-disabled-text">
|
|
VA filtering paused while editing
|
|
</span>
|
|
}
|
|
<!-- Persistent live region (shown in both modes) so a filter
|
|
change that arrives while editing is announced as pending. -->
|
|
<span class="va-filter-status" role="status" aria-live="polite">
|
|
@if (vaFilterStatus === 'pending') {
|
|
<span class="va-pending-text"> Filter change pending </span>
|
|
}
|
|
@if (vaFilterStatus === 'loading') {
|
|
<span class="va-loading-text"> Loading filter… </span>
|
|
}
|
|
</span>
|
|
</div>
|
|
}
|
|
|
|
@if (
|
|
licenceState.value.editor_rows_allowed !== Infinity &&
|
|
dataSource &&
|
|
dataSource.length > licenceState.value.editor_rows_allowed
|
|
) {
|
|
<p 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>-->
|
|
@if (submit) {
|
|
<div class="modal">
|
|
<!-- && 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">
|
|
@if (
|
|
totalRowsChanged > licenceState.value.submit_rows_limit &&
|
|
licenceState.value.submit_rows_limit !== Infinity
|
|
) {
|
|
<span 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@datacontroller.io</span
|
|
>
|
|
}
|
|
@if (tableTrue) {
|
|
<div 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@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>
|
|
@for (
|
|
duplicatePkIndex of duplicatePkIndexes;
|
|
track duplicatePkIndex;
|
|
let i = $index
|
|
) {
|
|
<span class="d-block">
|
|
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>
|
|
@for (cell of exceedCells; track cell) {
|
|
<p>{{ 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>
|
|
</main>
|
|
|
|
@if (nullVariables) {
|
|
<div class="modal z-index-highest">
|
|
<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">
|
|
@if (filter) {
|
|
<app-query #queryFilter></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">
|
|
@if (fileUnlockError) {
|
|
<p 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>
|
|
|
|
<app-confirm-modal
|
|
[open]="confirmModal.open"
|
|
[title]="confirmModal.title"
|
|
[message]="confirmModal.message"
|
|
(result)="onConfirmModalResult($event)"
|
|
></app-confirm-modal>
|
|
|
|
<app-bulk-validation-modal
|
|
[open]="bulkValidation.active"
|
|
[done]="bulkValidation.done"
|
|
[total]="bulkValidation.total"
|
|
(cancel)="cancelBulkValidation({ revert: true })"
|
|
></app-bulk-validation-modal>
|