src/app/shared/dc-tree/dc-tree.component.ts
OnInit
AfterViewInit
OnChanges
| encapsulation | ViewEncapsulation.None |
| selector | dc-tree |
| styleUrls | ./dc-tree.component.scss |
| templateUrl | ./dc-tree.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
HostListeners |
constructor(helperService: HelperService, licenceService: LicenceService)
|
|||||||||
|
Parameters :
|
| hasColumns | |
Type : boolean
|
|
Default value : false
|
|
| libraryList | |
Type : any[] | undefined
|
|
| paging | |
Type : boolean
|
|
Default value : true
|
|
| libraryOnClickEmitter | |
Type : EventEmitter
|
|
| tableOnClickEmitter | |
Type : EventEmitter
|
|
| scroll |
Arguments : '$event'
|
scroll(event: Event)
|
| Public collapseTreeItems |
collapseTreeItems(tree: any, itemToSkip: any)
|
|
Returns :
void
|
| columnOnClick |
columnOnClick(libColumn: any, library: any, libTable: any)
|
|
Returns :
void
|
| handleScroll | ||||||
handleScroll(event: Event)
|
||||||
Decorators :
@HostListener('scroll', ['$event'])
|
||||||
|
Parameters :
Returns :
void
|
| Public libColumnActive | ||||||
libColumnActive(libColumnUri: string)
|
||||||
|
Parameters :
Returns :
boolean
|
| libraryOnClick |
libraryOnClick(libid: string, library: any, libTreeNode: any)
|
|
Returns :
void
|
| libraryOnFilter |
libraryOnFilter()
|
|
Returns :
void
|
| Public libTabActive |
libTabActive(library: string, table: string)
|
|
Returns :
boolean
|
| Public loadMoreLibraries |
loadMoreLibraries()
|
|
Returns :
void
|
| ngAfterViewInit |
ngAfterViewInit()
|
|
Returns :
void
|
| ngOnChanges | ||||||
ngOnChanges(changes: SimpleChanges)
|
||||||
|
Parameters :
Returns :
void
|
| ngOnInit |
ngOnInit()
|
|
Returns :
void
|
| Public Async tableOnClick |
tableOnClick(tableuri: string, libTable: any, library: any)
|
|
Returns :
any
|
| treeNodeClicked |
treeNodeClicked(event: any, item: any, tree: any)
|
|
Returns :
void
|
| treeOnFilter |
treeOnFilter(array: any, arrToFilter: string)
|
|
Returns :
void
|
| Public column |
Type : string | undefined
|
| Public lib |
Type : any
|
Default value : ''
|
| Public librariesPaging |
Type : boolean
|
Default value : false
|
| Public librariesSearch |
Type : string
|
Default value : ''
|
| Public licenceState |
Type : unknown
|
Default value : this.licenceService.licenceState
|
| searchLibInputList |
Type : QueryList<any>
|
Default value : new QueryList()
|
Decorators :
@ViewChildren('searchLibTreeInput')
|
| Public table |
Type : any
|
Default value : ''
|
import {
AfterViewInit,
Component,
EventEmitter,
HostListener,
Input,
OnChanges,
OnInit,
Output,
QueryList,
SimpleChanges,
ViewChildren,
ViewEncapsulation
} from '@angular/core'
import { HelperService } from 'src/app/services/helper.service'
import { LicenceService } from 'src/app/services/licence.service'
import { globals } from 'src/app/_globals'
import { LibraryClickEmitter } from './models/LibraryClickEmitter'
import { TableClickEmitter } from './models/TableClickEmitter'
@Component({
selector: 'dc-tree',
templateUrl: './dc-tree.component.html',
styleUrls: ['./dc-tree.component.scss'],
encapsulation: ViewEncapsulation.None,
standalone: false
})
export class DcTreeComponent implements OnInit, AfterViewInit, OnChanges {
// REFACTOR NOTICE
// This component ideally should be used in whole app instead of `clr-tree` being copied again in every component
@ViewChildren('searchLibTreeInput')
searchLibInputList: QueryList<any> = new QueryList()
@Output() tableOnClickEmitter = new EventEmitter<TableClickEmitter>()
@Output() libraryOnClickEmitter = new EventEmitter<LibraryClickEmitter>()
@Input() hasColumns: boolean = false
@Input() paging: boolean = true
@Input() libraryList: any[] | undefined
public librariesSearch: string = ''
public lib: any = ''
public table: any = ''
public column: string | undefined
public librariesPaging: boolean = false
public licenceState = this.licenceService.licenceState
constructor(
private helperService: HelperService,
private licenceService: LicenceService
) {}
ngOnInit(): void {}
ngAfterViewInit(): void {
setTimeout(() => {
this.searchLibInputList.first.nativeElement.focus()
})
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.libraryList?.currentValue) {
if (this.libraryList) {
this.helperService.displayLibraries(this.libraryList)
}
}
}
treeOnFilter(array: any, arrToFilter: string) {
this.helperService.treeOnFilter(array, arrToFilter)
}
libraryOnFilter() {
this.helperService.libraryOnFilter(
this.libraryList,
this.librariesSearch,
'LIBRARYNAME'
)
globals.lineage.librariesSearch = this.librariesSearch
}
treeNodeClicked(event: any, item: any, tree: any) {
if (event.target.title === 'Collapse') {
this.collapseTreeItems(tree, item)
}
}
libraryOnClick(libid: string, library: any, libTreeNode: any) {
library['inForeground'] = true //When we programatically call this function, we make sure it is visible in the sidebar
const focusTableSearch = () =>
setTimeout(() =>
libTreeNode.contentContainer.nativeElement.parentElement
.querySelector('input')
.focus()
)
if (!library['tables']) {
library['loadingTables'] = true
this.libraryOnClickEmitter.emit({ libid, library, tablesLoaded: false })
const interval = setInterval(() => {
if (!library['loadingTables']) {
focusTableSearch()
clearInterval(interval)
}
}, 500)
} else {
library['expanded'] = !library['expanded']
this.libraryOnClickEmitter.emit({ libid, library, tablesLoaded: true })
}
if (library['expanded']) {
focusTableSearch()
}
this.collapseTreeItems(this.libraryList, library)
}
public async tableOnClick(tableuri: string, libTable: any, library: any) {
this.helperService.debounceCall(50, () => {
if (!this.hasColumns) {
this.tableOnClickEmitter.emit({
tableuri,
libTable,
library,
columnsLoaded: false
})
return
}
if (!libTable['columns']) {
libTable['expanded'] = !libTable['expanded']
libTable['loadingColumns'] = true
this.table = tableuri
this.tableOnClickEmitter.emit({
tableuri,
libTable,
library,
columnsLoaded: false
})
} else {
libTable['expanded'] = !libTable['expanded']
if (libTable['expanded'] === true) {
this.table = tableuri
this.tableOnClickEmitter.emit({
tableuri,
libTable,
library,
columnsLoaded: true
})
}
}
this.collapseTreeItems(library['tables'], libTable)
})
}
columnOnClick(libColumn: any, library: any, libTable: any) {
this.lib = library.LIBRARYID
this.table = libTable.TABLEURI
this.column = libColumn.COLURI
}
public libTabActive(library: string, table: string) {
if (!this.lib || !this.table) {
return false
}
return library === this.lib && table === this.table
}
public libColumnActive(libColumnUri: string) {
if (!this.column) {
return false
}
let splitedLibColumnUri = libColumnUri.split('\\')
let splitedColumnUri = this.column.split('\\')
return (
splitedLibColumnUri[splitedLibColumnUri.length - 1] ==
splitedColumnUri[splitedColumnUri.length - 1]
)
}
public collapseTreeItems(tree: any, itemToSkip: any) {
tree.forEach((item: any) => {
if (JSON.stringify(item) !== JSON.stringify(itemToSkip)) {
item['expanded'] = false
}
})
}
public loadMoreLibraries() {
if (!this.librariesPaging) {
this.librariesPaging = true
this.helperService.displayLibraries(this.libraryList, true)
this.librariesPaging = false
}
}
@HostListener('scroll', ['$event'])
handleScroll(event: Event) {
let element = event.target as HTMLElement
if (element) {
// When list scrolled to the bottom, load more libraries
if (
element.scrollTop >=
element.scrollHeight - element.offsetHeight - 10
) {
this.loadMoreLibraries()
}
}
}
}
<clr-tree>
@if (libraryList) {
<clr-tree-node class="search-node">
<div class="tree-search-wrapper">
<input
appStealFocus
clrInput
#searchLibTreeInput
placeholder="Libraries"
name="input"
[(ngModel)]="librariesSearch"
(keyup)="libraryOnFilter()"
autocomplete="off"
/>
@if (searchLibTreeInput.value.length < 1) {
<clr-icon shape="search"></clr-icon>
}
@if (searchLibTreeInput.value.length > 0) {
<clr-icon
(click)="librariesSearch = ''; libraryOnFilter()"
shape="times"
></clr-icon>
}
</div>
</clr-tree-node>
}
@for (library of libraryList; track library) {
@if (!library['hidden'] && library['inForeground']) {
<clr-tree-node
#libTreeNode
(click)="treeNodeClicked($event, library, libraryList)"
[(clrExpanded)]="library['expanded']"
[clrLoading]="library['loadingTables'] && !library.tables"
[class.clr-expanded]="library['expanded']"
>
<p
(click)="
lib = library.LIBRARYID;
libraryOnClick(lib || '', library, libTreeNode)
"
class="m-0 cursor-pointer"
>
<clr-icon shape="rack-server"></clr-icon>
{{ library.LIBRARYNAME }}
</p>
@if (library['tables']) {
<clr-tree-node class="search-node">
<div class="tree-search-wrapper">
<input
appStealFocus
clrInput
#searchTreeInput
placeholder="Tables"
name="input"
[(ngModel)]="library['searchString']"
(keyup)="treeOnFilter(library, 'tables')"
autocomplete="off"
/>
@if (searchTreeInput.value.length < 1) {
<clr-icon shape="search"></clr-icon>
}
@if (searchTreeInput.value.length > 0) {
<clr-icon
(click)="
searchTreeInput.value = '';
library['searchString'] = '';
treeOnFilter(library, 'tables.TABLENAME')
"
shape="times"
></clr-icon>
}
</div>
</clr-tree-node>
}
@for (
libTable of library['tables'];
track libTable;
let index = $index
) {
<clr-tree-node
(click)="treeNodeClicked($event, libTable, library['tables'])"
[(clrExpanded)]="libTable['expanded']"
[clrLoading]="libTable['loadingColumns'] && !libTable.columns"
[class.clr-expanded]="libTable['expanded']"
>
<clr-tooltip
*ngVar="
index + 1 >
licenceState.value.tables_in_library_limit as tableLocked
"
>
<button
clrTooltipTrigger
(click)="
!tableLocked
? tableOnClick(libTable.TABLEURI, libTable, library)
: ''
"
class="clr-treenode-link"
[class.dc-locked-control]="tableLocked"
[class.active]="libTabActive(library.LIBRARYREF, libTable)"
>
@switch (libTable.includes('-FC')) {
@case (true) {
<clr-icon shape="bolt"></clr-icon>
}
@case (false) {
<clr-icon shape="table"></clr-icon>
}
}
{{ libTable.replace('-FC', '') }}
</button>
<clr-tooltip-content
clrPosition="bottom-right"
clrSize="lg"
*clrIfOpen
>
@if (tableLocked) {
<span>
To unlock all tables, contact support@datacontroller.io
</span>
}
</clr-tooltip-content>
@if (hasColumns) {
@if (libTable['columns']) {
<clr-tree-node class="search-node">
<div class="tree-search-wrapper">
<input
appStealFocus
clrInput
#searchTreeInput
placeholder="Columns"
name="input"
[(ngModel)]="libTable['searchString']"
(keyup)="treeOnFilter(libTable, 'columns.COLNAME')"
autocomplete="off"
/>
@if (searchTreeInput.value.length < 1) {
<clr-icon shape="search"></clr-icon>
}
@if (searchTreeInput.value.length > 0) {
<clr-icon
(click)="
searchTreeInput.value = '';
libTable['searchString'] = '';
treeOnFilter(libTable, 'columns.COLNAME')
"
shape="times"
></clr-icon>
}
</div>
</clr-tree-node>
}
@for (libColumn of libTable['columns']; track libColumn) {
<clr-tree-node>
<button
(click)="columnOnClick(libColumn, library, libTable)"
class="clr-treenode-link"
[class.column-active]="libColumnActive(libColumn.COLURI)"
>
<clr-icon shape="objects"></clr-icon>
{{ libColumn.COLNAME }}
</button>
</clr-tree-node>
}
}
</clr-tooltip>
</clr-tree-node>
}
</clr-tree-node>
}
}
</clr-tree>
@if (librariesPaging) {
<div class="w-100 text-center">
<span class="spinner spinner-sm"> Loading... </span>
</div>
}
./dc-tree.component.scss