Files
dc/client/src/app/viewer/viewer.component.html
Mihajlo Medjedovic 69f687a85f
All checks were successful
Build / Build-and-ng-test (pull_request) Successful in 4m11s
Build / Build-and-test-development (pull_request) Successful in 8m34s
fix: commit git hooks checking lint
2025-06-11 13:11:30 +02:00

677 lines
21 KiB
HTML

<app-sidebar (scrolledToBottom)="loadMoreLibraries()">
<div *ngIf="librariesLoading" class="my-10-mx-auto text-center">
<clr-spinner clrMedium></clr-spinner>
</div>
<clr-tree>
<clr-tree-node *ngIf="libraries" class="search-node">
<div class="tree-search-wrapper">
<input
appStealFocus
clrInput
#searchLibTreeInput
[(ngModel)]="librariesSearch"
placeholder="Libraries"
name="input"
(keyup)="libraryOnFilter()"
autocomplete="off"
/>
<clr-icon
*ngIf="searchLibTreeInput.value.length < 1"
shape="search"
></clr-icon>
<clr-icon
*ngIf="searchLibTreeInput.value.length > 0"
(click)="librariesSearch = ''; libraryOnFilter()"
shape="times"
></clr-icon>
</div>
</clr-tree-node>
<ng-container *ngFor="let library of libraries">
<clr-tree-node
(click)="treeNodeClicked($event, library)"
*ngIf="!library['hidden'] && library['inForeground']"
[(clrExpanded)]="library['expanded']"
[clrLoading]="library['loadingTables'] && !library.tables"
[class.clr-expanded]="library['expanded']"
>
<p
(click)="
lib = library.LIBRARYREF;
libraryOnClick(library.LIBRARYREF, library)
"
class="m-0 cursor-pointer"
>
<clr-icon shape="rack-server"></clr-icon>
{{ library.LIBRARYNAME }}
</p>
<clr-tree-node *ngIf="library['tables']" class="search-node">
<div class="tree-search-wrapper">
<input
appStealFocus
clrInput
#searchTreeInput
[id]="'search_' + library.LIBRARYREF"
placeholder="Tables"
name="input"
[(ngModel)]="library['searchString']"
(keyup)="treeOnFilter(library, 'tables')"
autocomplete="off"
/>
<clr-icon
*ngIf="searchTreeInput.value.length < 1"
shape="search"
></clr-icon>
<clr-icon
*ngIf="searchTreeInput.value.length > 0"
(click)="
searchTreeInput.value = '';
library['searchString'] = '';
treeOnFilter(library, 'tables')
"
shape="times"
></clr-icon>
</div>
</clr-tree-node>
<clr-tree-node
*ngFor="let libTable of library['tables']; let index = index"
>
<clr-tooltip
*ngVar="
index + 1 >
licenceState.value.tables_in_library_limit as tableLocked
"
>
<button
clrTooltipTrigger
*ngIf="libTable.length > 0"
(click)="!tableLocked ? onTableClick(libTable, library) : ''"
class="clr-treenode-link"
[class.dc-locked-control]="tableLocked"
[class.active]="libTabActive(library.LIBRARYREF, libTable)"
>
<ng-container [ngSwitch]="libTable.includes('-FC')">
<clr-icon *ngSwitchCase="true" shape="bolt"></clr-icon>
<clr-icon *ngSwitchCase="false" shape="table"></clr-icon>
</ng-container>
{{ libTable.replace('-FC', '') }}
</button>
<ng-container *ngIf="tableLocked">
<clr-tooltip-content
clrPosition="bottom-right"
clrSize="lg"
*clrIfOpen
>
<span>
To unlock all tables, contact support&#64;datacontroller.io
</span>
</clr-tooltip-content>
</ng-container>
</clr-tooltip>
</clr-tree-node>
</clr-tree-node>
</ng-container>
</clr-tree>
<div *ngIf="librariesPaging" class="w-100 text-center">
<span class="spinner spinner-sm"> Loading... </span>
</div>
</app-sidebar>
<div class="content-area">
<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>
<div *ngIf="nullVariables" class="modal-backdrop" aria-hidden="true"></div>
<clr-modal [(clrModalOpen)]="openDownload" [clrModalSize]="'md'">
<h3 class="modal-title center text-center color-darker-gray">Download</h3>
<div class="modal-body">
<div class="clr-col-md-6">
<clr-select-container class="download-select">
<label>Please choose download format</label>
<select [(ngModel)]="downloadFormat" clrSelect>
<option value="CSV">CSV</option>
<option value="SAS">Datalines (cards file)</option>
<option value="PGSQL_DDL">DDL (PGSQL Flavour)</option>
<option value="SAS_DDL">DDL (SAS Flavour)</option>
<option value="TSQL_DDL">DDL (TSQL Flavour)</option>
<option value="EXCEL">Excel (.xlsx)</option>
<option value="MARKDOWN">Markdown (.md)</option>
</select>
</clr-select-container>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-sm btn-outline"
(click)="openDownload = false"
>
Cancel
</button>
<button
[id]="tableTitle"
type="submit"
class="btn btn-sm btn-success-outline"
(click)="
downloadFormat.includes('DDL') ? downloadDDL() : downloadData()
"
>
Ok
</button>
</div>
</clr-modal>
<clr-modal [(clrModalOpen)]="webQuery" [clrModalSize]="'lg'">
<h3 class="modal-title center text-center color-darker-gray">
Web Query URL
</h3>
<div class="modal-body web-query">
<div class="row">
<div class="clr-col-lg-12 clr-col-md-12 clr-col-sm-12 clr-col-xs-12">
<div class="card no-borders">
<div class="card-header d-flex justify-content-between">
<span>Copy the below into your preferred client tool:</span>
<div class="d-block mr-0" class="btn-group">
<div
class="radio btn"
(click)="webQueryTab = true; showWebQuery()"
>
<input
type="radio"
name="btn-group-demo-radios"
[checked]="webQueryTab"
/>
<label>TAB</label>
</div>
<div
class="radio btn"
(click)="webQueryTab = false; showWebQuery()"
>
<input
type="radio"
name="btn-group-demo-radios"
[checked]="!webQueryTab"
/>
<label>CSV</label>
</div>
</div>
</div>
<div class="card-block web-query-wrapper word-break-all">
<textarea
clrTextarea
class="web-query-text"
rows="4"
cols="50"
#cliCommandInput
(focus)="onCliCommandFocus($event)"
type="text"
[value]="webQueryText"
readonly
>
</textarea>
</div>
<div class="card-footer">
<button
class="btn btn-sm btn-link"
[ngxClipboard]="cliCommandInput"
(click)="copyToClip()"
>
copy to clipboard
</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-sm btn-outline"
(click)="webQuery = false"
>
close
</button>
<!-- <button type="submit" class="btn btn-sm btn-success-outline" (click)="downloadData()">Ok</button> -->
</div>
</clr-modal>
<clr-modal
[(clrModalOpen)]="filter"
[clrModalSize]="'xl'"
[clrModalClosable]="false"
aria-modal="true"
class="filter-modal"
>
<h3 class="modal-title center text-center color-darker-gray">
Filter for table:<span> {{ libTab }} </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-outline btn-sm"
(click)="filter = false; removeQuery()"
>
Cancel
</button>
<button
[clrLoading]="submitLoading"
type="submit"
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>
<div class="loadingSpinner" *ngIf="loadingTableView">
<span class="spinner"> Loading... </span>
<div class="mt-10">
<p cds-text="section">Loading Table Viewer</p>
</div>
</div>
<div
class="card no-borders h-100 d-flex clr-flex-column"
*ngIf="!loadingTableView"
>
<div
*ngIf="table"
class="header-row clr-row justify-content-between clr-justify-content-center w-100 m-0"
>
<section class="form-block table-search-wrapper sw clr-col-md">
<form class="d-flex align-items-center" clrForm>
<div class="input-wrapper">
<input
#searchEl
(keyup.enter)="searchTable(searchEl)"
clrInput
[type]="searchNumeric ? 'number' : 'text'"
placeholder="Search"
name="search-input"
/>
<clr-icon
*ngIf="!searchLoading"
(click)="searchTable(searchEl)"
shape="search"
></clr-icon>
<span *ngIf="searchLoading" class="spinner spinner-inline">
Loading...
</span>
</div>
<clr-checkbox-container>
<clr-checkbox-wrapper>
<input
type="checkbox"
clrCheckbox
[(ngModel)]="searchNumeric"
name="numeric_check"
/>
<label>Numeric</label>
</clr-checkbox-wrapper>
</clr-checkbox-container>
</form>
</section>
<div class="title-col clr-col-auto clr-flex-column clr-flex-sm-row">
<p
cds-text="section"
class="clr-flex-column d-flex clr-flex-sm-row clr-align-items-center clr-justify-content-center"
>
<clr-tooltip class="d-flex clr-align-items-center">
<clr-icon
clrTooltipTrigger
(click)="datasetInfo = true"
aria-label="View dataset meta info"
shape="info-circle"
class="is-highlight cursor-pointer"
size="24"
></clr-icon>
<clr-icon
*ngIf="tableTitle?.includes('-FC')"
shape="bolt"
class="color-yellow mr-5"
></clr-icon>
<span clrTooltipTrigger *ngIf="tableTitle && tableTitle.length > 0">
{{ tableTitle?.replace('-FC', '') }}
</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="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>
</p>
</div>
<div class="options-col clr-col-md">
<clr-dropdown
*ngIf="tableTitle && !abortActive"
class="options-dropdown"
[clrCloseMenuOnItemClick]="true"
>
<button
type="button"
class="btn btn-sm btn-outline filterSide"
clrDropdownTrigger
>
<clr-icon shape="cog" size="15"></clr-icon>
options
</button>
<clr-dropdown-menu clrPosition="bottom-right" *clrIfOpen>
<div (click)="newViewbox()" clrDropdownItem>
<clr-icon shape="view-cards"></clr-icon>
<span>Viewboxes</span>
</div>
<div
*ngIf="tableEditExists()"
(click)="editTable()"
clrDropdownItem
>
<clr-icon shape="pencil"></clr-icon>
<span>Edit</span>
</div>
<div *ngIf="tableuri" (click)="goToLineage()" clrDropdownItem>
<clr-icon shape="switch"></clr-icon>
<span>Lineage</span>
</div>
<div (click)="openQb()" clrDropdownItem>
<clr-icon shape="filter"></clr-icon>
<span>Filter</span>
</div>
<div (click)="openDownload = true" clrDropdownItem>
<clr-icon shape="download"></clr-icon>
<span>Download</span>
</div>
<div (click)="showWebQuery()" clrDropdownItem>
<clr-icon shape="download-cloud"></clr-icon>
<span>Web Query URL</span>
</div>
</clr-dropdown-menu>
</clr-dropdown>
</div>
<div
*ngIf="
queryText !== '1=1' && !['', ' '].includes(queryText) && !abortActive
"
class="clr-col-md-12 infoBar"
>
<span
>FILTER : <b>{{ queryText }}</b></span
>
</div>
</div>
<div
*ngIf="!lib && !table && !noDataReqErr && !noData"
class="no-table-selected"
>
<img
src="images/select-library.png"
class="select-table-icon"
alt="select a library icon"
/>
<h3 class="text-center color-gray mt-10" cds-text="section">
Please select a library
</h3>
</div>
<ng-container *ngIf="!noData && !noDataReqErr && !table && lib">
<div
class="header-row clr-row border-bottom-divider justify-content-between w-100 m-0"
>
<section
class="form-block table-search-wrapper sw clr-col-md"
></section>
<div class="title-col clr-col-auto mt-15 mb-15">
<p cds-text="section">
{{ lib }}
</p>
<clr-icon
(click)="reloadLibInfo()"
class="refresh-table"
shape="refresh"
></clr-icon>
</div>
<div class="options-col clr-col-md"></div>
</div>
<div class="text-center mt-10">
<clr-spinner *ngIf="libinfo === null" clrMedium></clr-spinner>
</div>
<div
*ngIf="libinfo !== null"
class="no-table-selected-info pointer-events-none"
>
<img
src="images/select-table.png"
class="select-table-icon"
alt="select table icon"
/>
<p class="text-center color-gray mt-10" cds-text="section">
Please select a table
</p>
</div>
<div *ngIf="libinfo !== null" class="libinfo m-0 clr-row">
<p *ngIf="libinfo.length < 1" class="text-center m-0 w-100">
No library info found. Click
<clr-icon
(click)="reloadLibInfo()"
class="refresh-table m-0"
shape="refresh"
></clr-icon>
button to refresh.
</p>
<ng-container *ngIf="libinfo.length > 0">
<table>
<tr *ngIf="libinfo[0].ENGINE !== ''">
<td class="m-0">ENGINE:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].ENGINE : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].LIBID !== ''">
<td class="m-0">LIBID:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].LIBID : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].LIBNAME !== ''">
<td class="m-0">LIBNAME:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].LIBNAME : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].LIBSIZE !== null">
<td class="m-0">LIBSIZE:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? (libinfo[0].LIBSIZE | convertSize) : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].OWNERS !== ''">
<td class="m-0">OWNERS:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].OWNERS : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].PATHS !== ''">
<td class="m-0">PATHS:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].PATHS : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].PERMS !== ''">
<td class="m-0">PERMS:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].PERMS : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].SCHEMAS !== ''">
<td class="m-0">SCHEMAS:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].SCHEMAS : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].TABLE_CNT !== null">
<td class="m-0">TABLE_CNT:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].TABLE_CNT : '' }}
</td>
</tr>
<tr *ngIf="libinfo[0].CATALOG_CNT !== null">
<td class="m-0">CATALOG_CNT:</td>
<td class="m-0 font-bold">
{{ libinfo[0] ? libinfo[0].CATALOG_CNT : '' }}
</td>
</tr>
</table>
</ng-container>
</div>
</ng-container>
<div *ngIf="noData || noDataReqErr" class="card-block noData">
<clr-icon shape="warning-standard" size="60" class="is-info"></clr-icon>
<h3 *ngIf="noData" class="text-center color-gray">
No data found with given conditions
</h3>
<h3 *ngIf="noDataReqErr" class="text-center color-gray">
No data found due to sas request error
</h3>
</div>
<div *ngIf="!noData && !noDataReqErr && table" class="clr-flex-1">
<hot-table
hotId="hotInstance"
id="hotTable"
className="htDark"
[multiColumnSorting]="true"
[viewportRowRenderingOffset]="50"
[data]="hotTable.data"
[colHeaders]="hotTable.colHeaders"
[columns]="hotTable.columns"
[copyPaste]="hotTable.copyPaste"
[contextMenu]="hotTable.contextMenu"
[filters]="true"
[dropdownMenu]="hotTable.dropdownMenu"
[height]="hotTable.height"
stretchH="all"
[modifyColWidth]="maxWidthCheker"
[cells]="hotTable.cells"
[maxRows]="hotTable.maxRows"
[manualColumnResize]="true"
[afterGetColHeader]="hotTable.afterGetColHeader"
[rowHeaders]="hotTable.rowHeaders"
[rowHeaderWidth]="hotTable.rowHeaderWidth"
[rowHeights]="hotTable.rowHeights"
[licenseKey]="hotTable.licenseKey"
>
</hot-table>
</div>
<div>
<p
*ngIf="
licenceState.value.viewer_rows_allowed !== Infinity &&
hotTable.data &&
hotTable.data.length > licenceState.value.viewer_rows_allowed
"
class="mt-2-i w-100 text-center"
>
To display more than {{ licenceState.value.viewer_rows_allowed }} rows,
contact <contact-link />
</p>
</div>
</div>
</div>
<app-dataset-info
[(open)]="datasetInfo"
[dsmeta]="dsmeta"
[versions]="versions"
(rowClicked)="datasetInfoModalRowClicked($event)"
>
</app-dataset-info>
<app-viewboxes [(viewboxModal)]="viewboxOpen"></app-viewboxes>