/// /// Copyright © 2016-2024 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 { BaseData, HasId } from '@shared/models/base-data'; import { EntitiesDataSource, EntitiesFetchFunction } from '@home/models/datasource/entity-datasource'; import { Observable, of } from 'rxjs'; import { emptyPageData } from '@shared/models/page/page-data'; import { DatePipe } from '@angular/common'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; import { EntityType, EntityTypeResource, EntityTypeTranslation } from '@shared/models/entity-type.models'; import { EntityComponent } from '@home/components/entity/entity.component'; import { Type } from '@angular/core'; import { EntityAction } from './entity-component.models'; import { HasUUID } from '@shared/models/id/has-uuid'; import { PageLink } from '@shared/models/page/page-link'; import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component'; import { ActivatedRoute } from '@angular/router'; import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; import { DAY, historyInterval } from '@shared/models/time/time.models'; import { IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models'; import { IEntityDetailsPageComponent } from '@home/models/entity/entity-details-page-component.models'; export type EntityBooleanFunction> = (entity: T) => boolean; export type EntityStringFunction> = (entity: T) => string; export type EntityVoidFunction> = (entity: T) => void; export type EntityIdsVoidFunction> = (ids: HasUUID[]) => void; export type EntityCountStringFunction = (count: number) => string; export type EntityTwoWayOperation> = (entity: T, originalEntity?: T) => Observable; export type EntityByIdOperation> = (id: HasUUID) => Observable; export type EntityIdOneWayOperation = (id: HasUUID) => Observable; export type EntityActionFunction> = (action: EntityAction) => boolean; export type CreateEntityOperation> = () => Observable; export type EntityRowClickFunction> = (event: Event, entity: T) => boolean; export type CellContentFunction> = (entity: T, key: string) => string; export type CellTooltipFunction> = (entity: T, key: string) => string | undefined; export type HeaderCellStyleFunction> = (key: string) => object; export type CellStyleFunction> = (entity: T, key: string) => object; export type CopyCellContent> = (entity: T, key: string, length: number) => object; export enum CellActionDescriptorType { 'DEFAULT', 'COPY_BUTTON'} export interface CellActionDescriptor> { name: string; nameFunction?: (entity: T) => string; icon?: string; iconFunction?: (entity: T) => string; style?: any; isEnabled: (entity: T) => boolean; onAction: ($event: MouseEvent, entity: T) => any; type?: CellActionDescriptorType; } export interface GroupActionDescriptor> { name: string; icon: string; isEnabled: boolean; onAction: ($event: MouseEvent, entities: T[]) => void; } export interface HeaderActionDescriptor { name: string; icon: string; isEnabled: () => boolean; onAction: ($event: MouseEvent) => void; } export type EntityTableColumnType = 'content' | 'action' | 'link' | 'clients'; export class BaseEntityTableColumn> { constructor(public type: EntityTableColumnType, public key: string, public title: string, public width: string = '0px', public sortable: boolean = true, public ignoreTranslate: boolean = false, public mobileHide: boolean = false) { } } export class EntityTableColumn> extends BaseEntityTableColumn { constructor(public key: string, public title: string, public width: string = '0px', public cellContentFunction: CellContentFunction = (entity, property) => entity[property] ? entity[property] : '', public cellStyleFunction: CellStyleFunction = () => ({}), public sortable: boolean = true, public headerCellStyleFunction: HeaderCellStyleFunction = () => ({}), public cellTooltipFunction: CellTooltipFunction = () => undefined, public isNumberColumn: boolean = false, public actionCell: CellActionDescriptor = null) { super('content', key, title, width, sortable); } } export class EntityActionTableColumn> extends BaseEntityTableColumn { constructor(public key: string, public title: string, public actionDescriptor: CellActionDescriptor, public width: string = '0px') { super('action', key, title, width, false); } } export class EntityLinkTableColumn> extends BaseEntityTableColumn { constructor(public key: string, public title: string, public width: string = '0px', public cellContentFunction: CellContentFunction = (entity, property) => entity[property] ? entity[property] : '', public entityURL: (entity) => string, public sortable: boolean = true) { super('link', key, title, width, sortable); } } export class DateEntityTableColumn> extends EntityTableColumn { constructor(key: string, title: string, datePipe: DatePipe, width: string = '0px', dateFormat: string = 'yyyy-MM-dd HH:mm:ss', cellStyleFunction: CellStyleFunction = () => ({})) { super(key, title, width, (entity, property) => datePipe.transform(entity[property], dateFormat), cellStyleFunction); } } export class ClientChipsEntityTableColumn> extends BaseEntityTableColumn { constructor(public key: string, public title: string, public width: string = '0px') { super('clients', key, title, width, false); } } export type EntityColumn> = EntityTableColumn | EntityActionTableColumn | EntityLinkTableColumn | ClientChipsEntityTableColumn; export class EntityTableConfig, P extends PageLink = PageLink, L extends BaseData = T> { constructor() {} private table: IEntitiesTableComponent = null; private entityDetailsPage: IEntityDetailsPageComponent = null; componentsData: any = null; loadDataOnInit = true; onLoadAction: (route: ActivatedRoute) => void = null; useTimePageLink = false; forAllTimeEnabled = false; defaultTimewindowInterval = historyInterval(DAY); entityType: EntityType = null; tableTitle = ''; hideTableTitle = false; selectionEnabled = true; searchEnabled = true; addEnabled = true; entitiesDeleteEnabled = true; detailsPanelEnabled = true; hideDetailsTabs = false; hideDetailsTabsOnEdit = true; rowPointer = false; actionsColumnTitle = null; entityTranslations: EntityTypeTranslation; entityResources: EntityTypeResource; entityComponent: Type>; entityTabsComponent: Type>; addDialogStyle = {}; defaultSortOrder: SortOrder = {property: 'createdTime', direction: Direction.DESC}; displayPagination = true; pageMode = true; defaultPageSize = 10; columns: Array> = []; cellActionDescriptors: Array> = []; groupActionDescriptors: Array> = []; headerActionDescriptors: Array = []; addActionDescriptors: Array = []; headerComponent: Type>; addEntity: CreateEntityOperation = null; dataSource: (dataLoadedFunction: (col?: number, row?: number) => void) => EntitiesDataSource = (dataLoadedFunction: (col?: number, row?: number) => void) => new EntitiesDataSource(this.entitiesFetchFunction, this.entitySelectionEnabled, dataLoadedFunction); detailsReadonly: EntityBooleanFunction = () => false; entitySelectionEnabled: EntityBooleanFunction = () => true; deleteEnabled: EntityBooleanFunction = () => true; deleteEntityTitle: EntityStringFunction = () => ''; deleteEntityContent: EntityStringFunction = () => ''; deleteEntitiesTitle: EntityCountStringFunction = () => ''; deleteEntitiesContent: EntityCountStringFunction = () => ''; loadEntity: EntityByIdOperation = () => of(); saveEntity: EntityTwoWayOperation = (entity, originalEntity) => of(entity); deleteEntity: EntityIdOneWayOperation = () => of(); entitiesFetchFunction: EntitiesFetchFunction = () => of(emptyPageData()); onEntityAction: EntityActionFunction = () => false; handleRowClick: EntityRowClickFunction = () => false; entityTitle: EntityStringFunction = (entity) => entity?.name; entityAdded: EntityVoidFunction = () => {}; entityUpdated: EntityVoidFunction = () => {}; entitiesDeleted: EntityIdsVoidFunction = () => {}; getTable(): IEntitiesTableComponent { return this.table; } setTable(table: IEntitiesTableComponent) { this.table = table; this.entityDetailsPage = null; } getEntityDetailsPage(): IEntityDetailsPageComponent { return this.entityDetailsPage; } setEntityDetailsPage(entityDetailsPage: IEntityDetailsPageComponent) { this.entityDetailsPage = entityDetailsPage; this.table = null; } updateData(closeDetails = false) { if (this.table) { this.table.updateData(closeDetails); } else if (this.entityDetailsPage) { this.entityDetailsPage.reload(); } } toggleEntityDetails($event: Event, entity: T) { if (this.table) { this.table.toggleEntityDetails($event, entity); } } isDetailsOpen(): boolean { if (this.table) { return this.table.isDetailsOpen; } else { return false; } } getActivatedRoute(): ActivatedRoute { if (this.table) { return this.table.route; } else { return null; } } } export const checkBoxCell = (value: boolean): string => `${value ? 'check_box' : 'check_box_outline_blank'}`;