thingsboard/ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts

322 lines
9.7 KiB
TypeScript
Raw Normal View History

2019-08-23 15:06:42 +03:00
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { PageLink } from '@shared/models/page/page-link';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { MatDialog } from '@angular/material/dialog';
import { DialogService } from '@core/services/dialog.service';
import { EntityRelationService } from '@core/http/entity-relation.service';
import { Direction, SortOrder } from '@shared/models/page/sort-order';
2019-08-27 20:07:09 +03:00
import { forkJoin, fromEvent, merge, Observable } from 'rxjs';
2019-08-23 15:06:42 +03:00
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
2019-08-27 20:07:09 +03:00
import {
EntityRelation,
EntityRelationInfo,
EntitySearchDirection,
entitySearchDirectionTranslations,
RelationTypeGroup
} from '@shared/models/relation.models';
2019-08-23 15:06:42 +03:00
import { EntityId } from '@shared/models/id/entity-id';
import { RelationsDatasource } from '../../models/datasource/relation-datasource';
2019-08-27 20:07:09 +03:00
import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component';
2019-08-23 15:06:42 +03:00
@Component({
selector: 'tb-relation-table',
templateUrl: './relation-table.component.html',
styleUrls: ['./relation-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RelationTableComponent extends PageComponent implements AfterViewInit, OnInit {
directions = EntitySearchDirection;
directionTypes = Object.keys(EntitySearchDirection);
directionTypeTranslations = entitySearchDirectionTranslations;
displayedColumns: string[];
direction: EntitySearchDirection;
pageLink: PageLink;
textSearchMode = false;
dataSource: RelationsDatasource;
activeValue = false;
dirtyValue = false;
entityIdValue: EntityId;
viewsInited = false;
@Input()
set active(active: boolean) {
if (this.activeValue !== active) {
this.activeValue = active;
if (this.activeValue && this.dirtyValue) {
this.dirtyValue = false;
if (this.viewsInited) {
this.updateData(true);
}
}
}
}
@Input()
set entityId(entityId: EntityId) {
if (this.entityIdValue !== entityId) {
this.entityIdValue = entityId;
if (this.viewsInited) {
this.resetSortAndFilter(this.activeValue);
if (!this.activeValue) {
this.dirtyValue = true;
}
}
}
}
@ViewChild('searchInput', {static: false}) searchInputField: ElementRef;
@ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
@ViewChild(MatSort, {static: false}) sort: MatSort;
constructor(protected store: Store<AppState>,
private entityRelationService: EntityRelationService,
public translate: TranslateService,
public dialog: MatDialog,
private dialogService: DialogService) {
super(store);
this.dirtyValue = !this.activeValue;
const sortOrder: SortOrder = { property: 'type', direction: Direction.ASC };
this.direction = EntitySearchDirection.FROM;
this.pageLink = new PageLink(10, 0, null, sortOrder);
this.dataSource = new RelationsDatasource(this.entityRelationService, this.translate);
this.updateColumns();
}
ngOnInit() {
}
updateColumns() {
if (this.direction === EntitySearchDirection.FROM) {
this.displayedColumns = ['select', 'type', 'toEntityTypeName', 'toName', 'actions'];
} else {
this.displayedColumns = ['select', 'type', 'fromEntityTypeName', 'fromName', 'actions'];
}
}
directionChanged(direction: EntitySearchDirection) {
this.direction = direction;
this.updateColumns();
this.updateData(true);
}
ngAfterViewInit() {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.paginator.pageIndex = 0;
this.updateData();
})
)
.subscribe();
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page)
.pipe(
tap(() => this.updateData())
)
.subscribe();
this.viewsInited = true;
if (this.activeValue && this.entityIdValue) {
this.updateData(true);
}
}
updateData(reload: boolean = false) {
this.pageLink.page = this.paginator.pageIndex;
this.pageLink.pageSize = this.paginator.pageSize;
this.pageLink.sortOrder.property = this.sort.active;
this.pageLink.sortOrder.direction = Direction[this.sort.direction.toUpperCase()];
this.dataSource.loadRelations(this.direction, this.entityIdValue, this.pageLink, reload);
}
enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
setTimeout(() => {
this.searchInputField.nativeElement.focus();
this.searchInputField.nativeElement.setSelectionRange(0, 0);
}, 10);
}
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
this.paginator.pageIndex = 0;
this.updateData();
}
resetSortAndFilter(update: boolean = true) {
this.direction = EntitySearchDirection.FROM;
this.updateColumns();
this.pageLink.textSearch = null;
this.paginator.pageIndex = 0;
const sortable = this.sort.sortables.get('type');
this.sort.active = sortable.id;
this.sort.direction = 'asc';
if (update) {
this.updateData(true);
}
}
reloadRelations() {
this.updateData(true);
}
addRelation($event: Event) {
this.openRelationDialog($event);
}
editRelation($event: Event, relation: EntityRelationInfo) {
this.openRelationDialog($event, relation);
}
deleteRelation($event: Event, relation: EntityRelationInfo) {
if ($event) {
$event.stopPropagation();
}
2019-08-27 20:07:09 +03:00
let title;
let content;
if (this.direction === EntitySearchDirection.FROM) {
title = this.translate.instant('relation.delete-to-relation-title', {entityName: relation.toName});
content = this.translate.instant('relation.delete-to-relation-text', {entityName: relation.toName});
} else {
title = this.translate.instant('relation.delete-from-relation-title', {entityName: relation.fromName});
content = this.translate.instant('relation.delete-from-relation-text', {entityName: relation.fromName});
}
2019-08-23 15:06:42 +03:00
2019-08-27 20:07:09 +03:00
this.dialogService.confirm(
title,
content,
this.translate.instant('action.no'),
this.translate.instant('action.yes'),
true
).subscribe((result) => {
if (result) {
this.entityRelationService.deleteRelation(
relation.from,
relation.type,
relation.to
).subscribe(
() => {
this.reloadRelations();
}
);
}
});
2019-08-23 15:06:42 +03:00
}
deleteRelations($event: Event) {
if ($event) {
$event.stopPropagation();
}
if (this.dataSource.selection.selected.length > 0) {
2019-08-27 20:07:09 +03:00
let title;
let content;
if (this.direction === EntitySearchDirection.FROM) {
title = this.translate.instant('relation.delete-to-relations-title', {count: this.dataSource.selection.selected.length});
content = this.translate.instant('relation.delete-to-relations-text');
} else {
title = this.translate.instant('relation.delete-from-relations-title', {count: this.dataSource.selection.selected.length});
content = this.translate.instant('relation.delete-from-relations-text');
}
this.dialogService.confirm(
title,
content,
this.translate.instant('action.no'),
this.translate.instant('action.yes'),
true
).subscribe((result) => {
if (result) {
const tasks: Observable<any>[] = [];
this.dataSource.selection.selected.forEach((relation) => {
tasks.push(this.entityRelationService.deleteRelation(
relation.from,
relation.type,
relation.to
));
});
forkJoin(tasks).subscribe(
() => {
this.reloadRelations();
}
);
}
});
2019-08-23 15:06:42 +03:00
}
}
2019-08-27 20:07:09 +03:00
openRelationDialog($event: Event, relation: EntityRelation = null) {
2019-08-23 15:06:42 +03:00
if ($event) {
$event.stopPropagation();
}
2019-08-27 20:07:09 +03:00
let isAdd = false;
if (!relation) {
isAdd = true;
relation = {
from: null,
to: null,
type: null,
typeGroup: RelationTypeGroup.COMMON
};
if (this.direction === EntitySearchDirection.FROM) {
relation.from = this.entityIdValue;
} else {
relation.to = this.entityIdValue;
}
}
this.dialog.open<RelationDialogComponent, RelationDialogData, boolean>(RelationDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
isAdd,
direction: this.direction,
relation: {...relation}
}
}).afterClosed().subscribe(
(res) => {
if (res) {
this.reloadRelations();
}
}
);
}
2019-08-23 15:06:42 +03:00
}