660 lines
20 KiB
HTML
660 lines
20 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
|
|
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
|
|
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.table-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>
|
|
<clr-tooltip-content
|
|
clrPosition="bottom-right"
|
|
clrSize="lg"
|
|
*clrIfOpen
|
|
>
|
|
<span *ngIf="tableLocked">
|
|
To unlock all tables, contact support@datacontroller.io
|
|
</span>
|
|
</clr-tooltip-content>
|
|
</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">
|
|
<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 word-break-all">
|
|
<textarea
|
|
class="web-query-text w-100"
|
|
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>
|
|
<h4>Loading table viewer</h4>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card 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">
|
|
<clr-icon
|
|
(click)="datasetInfo = true"
|
|
shape="info-circle"
|
|
class="is-highlight cursor-pointer"
|
|
size="24"
|
|
></clr-icon>
|
|
|
|
<clr-icon
|
|
*ngIf="tableTitle?.includes('-FC')"
|
|
shape="bolt"
|
|
class="color-yellow mt-5 mr-5"
|
|
></clr-icon>
|
|
|
|
<h3
|
|
*ngIf="tableTitle && tableTitle.length > 0"
|
|
class="viewerTitle clr-flex-column d-flex clr-flex-sm-row clr-align-items-center"
|
|
>
|
|
{{ tableTitle?.replace('-FC', '') }}
|
|
|
|
<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>
|
|
</h3>
|
|
</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>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-success-outline"
|
|
(click)="newViewbox()"
|
|
clrDropdownItem
|
|
>
|
|
<clr-icon shape="view-cards"></clr-icon>
|
|
<span>Viewboxes</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-success-outline"
|
|
*ngIf="tableEditExists()"
|
|
(click)="editTable()"
|
|
clrDropdownItem
|
|
>
|
|
<clr-icon shape="pencil"></clr-icon>
|
|
<span>Edit</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-success-outline"
|
|
*ngIf="tableuri"
|
|
(click)="goToLineage()"
|
|
clrDropdownItem
|
|
>
|
|
<clr-icon shape="switch"></clr-icon>
|
|
<span>Lineage</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-outline btn-block"
|
|
(click)="openQb()"
|
|
clrDropdownItem
|
|
>
|
|
<clr-icon shape="filter"></clr-icon>
|
|
<span>Filter</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-success-outline"
|
|
(click)="openDownload = true"
|
|
clrDropdownItem
|
|
>
|
|
<clr-icon shape="download"></clr-icon>
|
|
<span>Download</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="btn btn-sm btn-success-outline"
|
|
(click)="showWebQuery()"
|
|
clrDropdownItem
|
|
>
|
|
<clr-icon shape="download-cloud"></clr-icon>
|
|
<span>Web Query URL</span>
|
|
</button>
|
|
</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"
|
|
>
|
|
<clr-icon
|
|
shape="warning-standard"
|
|
size="60"
|
|
class="is-info icon-dc-fill"
|
|
></clr-icon>
|
|
<h3 class="text-center color-gray">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">
|
|
<h3 class="viewerTitle mt-17">
|
|
{{ lib }}
|
|
</h3>
|
|
<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"
|
|
>
|
|
<clr-icon
|
|
shape="info-standard"
|
|
size="40"
|
|
class="is-info icon-dc-fill"
|
|
></clr-icon>
|
|
<h3 class="text-center color-gray">Please select a table</h3>
|
|
</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>
|
|
</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"
|
|
[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"
|
|
[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"></app-dataset-info>
|
|
|
|
<app-viewboxes [(viewboxModal)]="viewboxOpen"></app-viewboxes>
|