Browse Source

UI: Add cache cellContent, cellStyle, rowStyle in entity tables widget

pull/4732/head
Vladyslav_Prykhodko 5 years ago
parent
commit
a0623e8e86
  1. 2
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts
  2. 10
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html
  3. 151
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts
  4. 10
      ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html
  5. 158
      ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts
  6. 18
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html
  7. 167
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts

2
ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts

@ -528,7 +528,7 @@ export class EntitiesTableComponent extends PageComponent implements AfterViewIn
const col = this.entitiesTableConfig.columns.indexOf(column);
const index = row * this.entitiesTableConfig.columns.length + col;
let res = this.cellContentCache[index];
if (!res) {
if (isUndefined(res)) {
res = this.domSanitizer.bypassSecurityTrustHtml(column.cellContentFunction(entity, column.key));
this.cellContentCache[index] = res;
}

10
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html

@ -81,9 +81,9 @@
<mat-header-cell [ngStyle]="headerStyle(column)" *matHeaderCellDef mat-sort-header [disabled]="isSorting(column)">
{{ column.title }}
</mat-header-cell>
<mat-cell *matCellDef="let alarm;"
[innerHTML]="cellContent(alarm, column)"
[ngStyle]="cellStyle(alarm, column)">
<mat-cell *matCellDef="let alarm; let row = index"
[innerHTML]="cellContent(alarm, column, row)"
[ngStyle]="cellStyle(alarm, column, row)">
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" [stickyEnd]="enableStickyAction">
@ -125,8 +125,8 @@
'mat-selected': alarmsDatasource.isSelected(alarm),
'tb-current-entity': alarmsDatasource.isCurrentAlarm(alarm),
'invisible': alarmsDatasource.dataLoading}"
*matRowDef="let alarm; columns: displayedColumns;"
[ngStyle]="rowStyle(alarm)"
*matRowDef="let alarm; columns: displayedColumns; let row = index"
[ngStyle]="rowStyle(alarm, row)"
(click)="onRowClick($event, alarm)"></mat-row>
</table>
<span [fxShow]="(alarmsDatasource.isEmpty() | async) && !alarmsDatasource.dataLoading"

151
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts

@ -35,7 +35,15 @@ import { DataKey, WidgetActionDescriptor, WidgetConfig } from '@shared/models/wi
import { IWidgetSubscription } from '@core/api/widget-api.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { createLabelFromDatasource, deepClone, hashCode, isDefined, isNumber, isObject } from '@core/utils';
import {
createLabelFromDatasource,
deepClone,
hashCode,
isDefined,
isNumber,
isObject,
isUndefined
} from '@core/utils';
import cssjs from '@core/css/css';
import { sortItems } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
@ -155,6 +163,10 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
public actionCellDescriptors: AlarmWidgetActionDescriptor[] = [];
public alarmsDatasource: AlarmsDatasource;
private cellContentCache: Array<any> = [];
private cellStyleCache: Array<any> = [];
private rowStyleCache: Array<any> = [];
private settings: AlarmsTableWidgetSettings;
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
@ -261,6 +273,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
public onDataUpdated() {
this.updateTitle(true);
this.alarmsDatasource.updateAlarms();
this.clearCache();
}
public pageLinkSortDirection(): SortDirection {
@ -484,6 +497,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
if (this.actionCellDescriptors.length) {
this.displayedColumns.push('actions');
}
this.clearCache();
}
} as DisplayColumnsPanelData
},
@ -609,91 +623,100 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
return widthStyle(columnWidth);
}
public rowStyle(alarm: AlarmDataInfo): any {
let style: any = {};
if (alarm) {
if (this.rowStylesInfo.useRowStyleFunction && this.rowStylesInfo.rowStyleFunction) {
public rowStyle(alarm: AlarmDataInfo, row: number): any {
let res = this.rowStyleCache[row];
if (!res) {
res = {};
if (alarm && this.rowStylesInfo.useRowStyleFunction && this.rowStylesInfo.rowStyleFunction) {
try {
style = this.rowStylesInfo.rowStyleFunction(alarm, this.ctx);
if (!isObject(style)) {
throw new TypeError(`${style === null ? 'null' : typeof style} instead of style object`);
res = this.rowStylesInfo.rowStyleFunction(alarm, this.ctx);
if (!isObject(res)) {
throw new TypeError(`${res === null ? 'null' : typeof res} instead of style object`);
}
if (Array.isArray(style)) {
if (Array.isArray(res)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
style = {};
res = {};
console.warn(`Row style function in widget '${this.ctx.widgetTitle}' ` +
`returns '${e}'. Please check your row style function.`);
}
} else {
style = {};
}
this.rowStyleCache[row] = res;
}
return style;
return res;
}
public cellStyle(alarm: AlarmDataInfo, key: EntityColumn): any {
let style: any = {};
if (alarm && key) {
const styleInfo = this.stylesInfo[key.def];
const value = getAlarmValue(alarm, key);
if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) {
try {
style = styleInfo.cellStyleFunction(value, alarm, this.ctx);
if (!isObject(style)) {
throw new TypeError(`${style === null ? 'null' : typeof style} instead of style object`);
}
if (Array.isArray(style)) {
throw new TypeError(`Array instead of style object`);
public cellStyle(alarm: AlarmDataInfo, key: EntityColumn, row: number): any {
const col = this.columns.indexOf(key);
const index = row * this.columns.length + col;
let res = this.cellStyleCache[index];
if (!res) {
res = {};
if (alarm && key) {
const styleInfo = this.stylesInfo[key.def];
const value = getAlarmValue(alarm, key);
if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) {
try {
res = styleInfo.cellStyleFunction(value, alarm, this.ctx);
if (!isObject(res)) {
throw new TypeError(`${res === null ? 'null' : typeof res} instead of style object`);
}
if (Array.isArray(res)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
res = {};
console.warn(`Cell style function for data key '${key.label}' in widget '${this.ctx.widgetTitle}' ` +
`returns '${e}'. Please check your cell style function.`);
}
} catch (e) {
style = {};
console.warn(`Cell style function for data key '${key.label}' in widget '${this.ctx.widgetTitle}' ` +
`returns '${e}'. Please check your cell style function.`);
} else {
res = this.defaultStyle(key, value);
}
} else {
style = this.defaultStyle(key, value);
}
this.cellStyleCache[index] = res;
}
if (!style.width) {
if (!res.width) {
const columnWidth = this.columnWidth[key.def];
style = {...style, ...widthStyle(columnWidth)};
res = Object.assign(res, widthStyle(columnWidth));
}
return style;
return res;
}
public cellContent(alarm: AlarmDataInfo, key: EntityColumn): SafeHtml {
if (alarm && key) {
const contentInfo = this.contentsInfo[key.def];
const value = getAlarmValue(alarm, key);
let content = '';
if (contentInfo.useCellContentFunction && contentInfo.cellContentFunction) {
try {
content = contentInfo.cellContentFunction(value, alarm, this.ctx);
} catch (e) {
content = '' + value;
public cellContent(alarm: AlarmDataInfo, key: EntityColumn, row: number): SafeHtml {
const col = this.columns.indexOf(key);
const index = row * this.columns.length + col;
let res = this.cellContentCache[index];
if (isUndefined(res)) {
res = '';
if (alarm && key) {
const contentInfo = this.contentsInfo[key.def];
const value = getAlarmValue(alarm, key);
let content = '';
if (contentInfo.useCellContentFunction && contentInfo.cellContentFunction) {
try {
content = contentInfo.cellContentFunction(value, alarm, this.ctx);
} catch (e) {
content = '' + value;
}
} else {
content = this.defaultContent(key, contentInfo, value);
}
} else {
content = this.defaultContent(key, contentInfo, value);
}
if (!isDefined(content)) {
return '';
} else {
content = this.utils.customTranslation(content, content);
switch (typeof content) {
case 'string':
return this.domSanitizer.bypassSecurityTrustHtml(content);
default:
return content;
if (isDefined(content)) {
content = this.utils.customTranslation(content, content);
switch (typeof content) {
case 'string':
res = this.domSanitizer.bypassSecurityTrustHtml(content);
break;
default:
res = content;
}
}
}
} else {
return '';
this.cellContentCache[index] = res;
}
return res;
}
public onRowClick($event: Event, alarm: AlarmDataInfo) {
@ -936,6 +959,12 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
isSorting(column: EntityColumn): boolean {
return column.type === DataKeyType.alarm && column.name.startsWith('details.');
}
private clearCache() {
this.cellContentCache.length = 0;
this.cellStyleCache.length = 0;
this.rowStyleCache.length = 0;
}
}
class AlarmsDatasource implements DataSource<AlarmDataInfo> {

10
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html

@ -42,9 +42,9 @@
matSort [matSortActive]="sortOrderProperty" [matSortDirection]="pageLinkSortDirection()" matSortDisableClear>
<ng-container [matColumnDef]="column.def" *ngFor="let column of columns; trackBy: trackByColumnDef;">
<mat-header-cell [ngStyle]="headerStyle(column)" *matHeaderCellDef mat-sort-header> {{ column.title }} </mat-header-cell>
<mat-cell *matCellDef="let entity;"
[innerHTML]="cellContent(entity, column)"
[ngStyle]="cellStyle(entity, column)">
<mat-cell *matCellDef="let entity; let row = index"
[innerHTML]="cellContent(entity, column, row)"
[ngStyle]="cellStyle(entity, column, row)">
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" [stickyEnd]="enableStickyAction">
@ -84,8 +84,8 @@
<mat-header-row *matHeaderRowDef="displayedColumns; sticky: enableStickyHeader"></mat-header-row>
<mat-row [ngClass]="{'tb-current-entity': entityDatasource.isCurrentEntity(entity),
'invisible': entityDatasource.dataLoading}"
*matRowDef="let entity; columns: displayedColumns;"
[ngStyle]="rowStyle(entity)"
*matRowDef="let entity; columns: displayedColumns; let row = index"
[ngStyle]="rowStyle(entity, row)"
(click)="onRowClick($event, entity)" (dblclick)="onRowClick($event, entity, true)"></mat-row>
</table>
<span [fxShow]="(entityDatasource.isEmpty() | async) && !entityDatasource.dataLoading"

158
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts

@ -40,7 +40,16 @@ import {
import { IWidgetSubscription } from '@core/api/widget-api.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { createLabelFromDatasource, deepClone, hashCode, isDefined, isNumber, isObject } from '@core/utils';
import {
createLabelFromDatasource,
deepClone,
hashCode,
isDefined,
isNumber,
isObject,
isString,
isUndefined
} from '@core/utils';
import cssjs from '@core/css/css';
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
@ -131,6 +140,10 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
public actionCellDescriptors: WidgetActionDescriptor[];
public entityDatasource: EntityDatasource;
private cellContentCache: Array<any> = [];
private cellStyleCache: Array<any> = [];
private rowStyleCache: Array<any> = [];
private settings: EntitiesTableWidgetSettings;
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
@ -222,6 +235,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
public onDataUpdated() {
this.updateTitle(true);
this.entityDatasource.dataUpdated();
this.clearCache();
}
public pageLinkSortDirection(): SortDirection {
@ -460,6 +474,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
if (this.actionCellDescriptors.length) {
this.displayedColumns.push('actions');
}
this.clearCache();
}
} as DisplayColumnsPanelData
},
@ -535,91 +550,98 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
return widthStyle(columnWidth);
}
public rowStyle(entity: EntityData): any {
let style: any = {};
if (entity) {
if (this.rowStylesInfo.useRowStyleFunction && this.rowStylesInfo.rowStyleFunction) {
public rowStyle(entity: EntityData, row: number): any {
let res = this.rowStyleCache[row];
if (!res) {
res = {};
if (entity && this.rowStylesInfo.useRowStyleFunction && this.rowStylesInfo.rowStyleFunction) {
try {
style = this.rowStylesInfo.rowStyleFunction(entity, this.ctx);
if (!isObject(style)) {
throw new TypeError(`${style === null ? 'null' : typeof style} instead of style object`);
res = this.rowStylesInfo.rowStyleFunction(entity, this.ctx);
if (!isObject(res)) {
throw new TypeError(`${res === null ? 'null' : typeof res} instead of style object`);
}
if (Array.isArray(style)) {
if (Array.isArray(res)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
style = {};
res = {};
console.warn(`Row style function in widget '${this.ctx.widgetTitle}' ` +
`returns '${e}'. Please check your row style function.`);
}
} else {
style = {};
}
this.rowStyleCache[row] = res;
}
return style;
}
public cellStyle(entity: EntityData, key: EntityColumn): any {
let style: any = {};
if (entity && key) {
const styleInfo = this.stylesInfo[key.def];
const value = getEntityValue(entity, key);
if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) {
try {
style = styleInfo.cellStyleFunction(value, entity, this.ctx);
if (!isObject(style)) {
throw new TypeError(`${style === null ? 'null' : typeof style} instead of style object`);
}
if (Array.isArray(style)) {
throw new TypeError(`Array instead of style object`);
return res;
}
public cellStyle(entity: EntityData, key: EntityColumn, row: number): any {
const col = this.columns.indexOf(key);
const index = row * this.columns.length + col;
let res = this.cellStyleCache[index];
if (!res) {
res = {};
if (entity && key) {
const styleInfo = this.stylesInfo[key.def];
const value = getEntityValue(entity, key);
if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) {
try {
res = styleInfo.cellStyleFunction(value, entity, this.ctx);
if (!isObject(res)) {
throw new TypeError(`${res === null ? 'null' : typeof res} instead of style object`);
}
if (Array.isArray(res)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
res = {};
console.warn(`Cell style function for data key '${key.label}' in widget '${this.ctx.widgetTitle}' ` +
`returns '${e}'. Please check your cell style function.`);
}
} catch (e) {
style = {};
console.warn(`Cell style function for data key '${key.label}' in widget '${this.ctx.widgetTitle}' ` +
`returns '${e}'. Please check your cell style function.`);
}
} else {
style = {};
this.cellStyleCache[index] = res;
}
}
if (!style.width) {
if (!res.width) {
const columnWidth = this.columnWidth[key.def];
style = {...style, ...widthStyle(columnWidth)};
res = Object.assign(res, widthStyle(columnWidth));
}
return style;
}
public cellContent(entity: EntityData, key: EntityColumn): SafeHtml {
if (entity && key) {
const contentInfo = this.contentsInfo[key.def];
const value = getEntityValue(entity, key);
let content: string;
if (contentInfo.useCellContentFunction && contentInfo.cellContentFunction) {
try {
content = contentInfo.cellContentFunction(value, entity, this.ctx);
} catch (e) {
content = '' + value;
return res;
}
public cellContent(entity: EntityData, key: EntityColumn, row: number): SafeHtml {
const col = this.columns.indexOf(key);
const index = row * this.columns.length + col;
let res = this.cellContentCache[index];
if (isUndefined(res)) {
res = '';
if (entity && key) {
const contentInfo = this.contentsInfo[key.def];
const value = getEntityValue(entity, key);
let content: string;
if (contentInfo.useCellContentFunction && contentInfo.cellContentFunction) {
try {
content = contentInfo.cellContentFunction(value, entity, this.ctx);
} catch (e) {
content = '' + value;
}
} else {
content = this.defaultContent(key, contentInfo, value);
}
} else {
content = this.defaultContent(key, contentInfo, value);
}
if (!isDefined(content)) {
return '';
} else {
content = this.utils.customTranslation(content, content);
switch (typeof content) {
case 'string':
return this.domSanitizer.bypassSecurityTrustHtml(content);
default:
return content;
if (isDefined(content)) {
content = this.utils.customTranslation(content, content);
switch (typeof content) {
case 'string':
res = this.domSanitizer.bypassSecurityTrustHtml(content);
break;
default:
res = content;
}
}
}
} else {
return '';
this.cellContentCache[index] = res;
}
return res;
}
private defaultContent(key: EntityColumn, contentInfo: CellContentInfo, value: any): any {
@ -672,6 +694,12 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
}
this.ctx.actionsApi.handleWidgetAction($event, actionDescriptor, entityId, entityName, {entity}, entityLabel);
}
private clearCache() {
this.cellContentCache.length = 0;
this.cellStyleCache.length = 0;
this.rowStyleCache.length = 0;
}
}
class EntityDatasource implements DataSource<EntityData> {

18
ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html

@ -39,23 +39,23 @@
</mat-toolbar>
<mat-tab-group [ngClass]="{'tb-headless': sources.length === 1}" fxFlex
[(selectedIndex)]="sourceIndex" (selectedIndexChange)="onSourceIndexChanged()">
<mat-tab *ngFor="let source of sources; trackBy: trackBySourcesIndex; let index = index;" label="{{getTabLabel(source)}}">
<mat-tab *ngFor="let source of sources; trackBy: trackBySourcesIndex; let index = index;" [label]="getTabLabel(source)">
<ng-template [ngIf]="isActiveTab(index)">
<div fxFlex class="table-container">
<table mat-table [dataSource]="source.timeseriesDatasource" [trackBy]="trackByRowTimestamp"
matSort [matSortActive]="source.pageLink.sortOrder.property" [matSortDirection]="source.pageLink.sortDirection()" matSortDisableClear>
<ng-container *ngIf="showTimestamp" [matColumnDef]="'0'">
<mat-header-cell *matHeaderCellDef mat-sort-header>Timestamp</mat-header-cell>
<mat-cell *matCellDef="let row;"
[innerHTML]="cellContent(source, 0, row, row[0])"
[ngStyle]="cellStyle(source, 0, row, row[0])">
<mat-cell *matCellDef="let row; let rowIndex = index"
[innerHTML]="cellContent(source, 0, row, row[0], rowIndex)"
[ngStyle]="cellStyle(source, 0, row, row[0], rowIndex)">
</mat-cell>
</ng-container>
<ng-container [matColumnDef]="h.index + ''" *ngFor="let h of source.header; trackBy: trackByColumnIndex;">
<mat-header-cell *matHeaderCellDef mat-sort-header> {{ h.dataKey.label }} </mat-header-cell>
<mat-cell *matCellDef="let row;"
[innerHTML]="cellContent(source, h.index, row, row[h.index])"
[ngStyle]="cellStyle(source, h.index, row, row[h.index])">
<mat-cell *matCellDef="let row; let rowIndex = index"
[innerHTML]="cellContent(source, h.index, row, row[h.index], rowIndex)"
[ngStyle]="cellStyle(source, h.index, row, row[h.index], rowIndex)">
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" [stickyEnd]="enableStickyAction">
@ -93,8 +93,8 @@
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="source.displayedColumns; sticky: enableStickyHeader"></mat-header-row>
<mat-row *matRowDef="let row; columns: source.displayedColumns;"
[ngStyle]="rowStyle(source, row)"
<mat-row *matRowDef="let row; columns: source.displayedColumns; let rowIndex = index"
[ngStyle]="rowStyle(source, row, rowIndex)"
(click)="onRowClick($event, row)"></mat-row>
</table>
<span [fxShow]="source.timeseriesDatasource.isEmpty() | async"

167
ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts

@ -40,7 +40,7 @@ import {
} from '@shared/models/widget.models';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { hashCode, isDefined, isNumber, isObject } from '@core/utils';
import { hashCode, isDefined, isNumber, isObject, isUndefined } from '@core/utils';
import cssjs from '@core/css/css';
import { PageLink } from '@shared/models/page/page-link';
import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order';
@ -120,6 +120,10 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
public sources: TimeseriesTableSource[];
public sourceIndex: number;
private cellContentCache: Array<any> = [];
private cellStyleCache: Array<any> = [];
private rowStyleCache: Array<any> = [];
private settings: TimeseriesTableWidgetSettings;
private widgetConfig: WidgetConfig;
private data: Array<DatasourceData>;
@ -194,6 +198,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
public onDataUpdated() {
this.updateCurrentSourceData();
this.clearCache();
}
private initialize() {
@ -337,6 +342,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
onSourceIndexChanged() {
this.updateCurrentSourceData();
this.updateActiveEntityInfo();
this.clearCache();
}
private enterFilterMode() {
@ -378,6 +384,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
source.pageLink.sortOrder.property = sort.active;
source.pageLink.sortOrder.direction = Direction[sort.direction.toUpperCase()];
source.timeseriesDatasource.loadRows();
this.clearCache();
this.ctx.detectChanges();
}
@ -397,94 +404,109 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
return source.datasource.entityId;
}
public rowStyle(source: TimeseriesTableSource, row: TimeseriesRow): any {
let style: any = {};
if (this.rowStylesInfo.useRowStyleFunction && this.rowStylesInfo.rowStyleFunction) {
try {
const rowData = source.rowDataTemplate;
rowData.Timestamp = row[0];
source.header.forEach((headerInfo) => {
rowData[headerInfo.dataKey.name] = row[headerInfo.index];
});
style = this.rowStylesInfo.rowStyleFunction(rowData, this.ctx);
if (!isObject(style)) {
throw new TypeError(`${style === null ? 'null' : typeof style} instead of style object`);
}
if (Array.isArray(style)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
style = {};
console.warn(`Row style function in widget ` +
`'${this.ctx.widgetConfig.title}' returns '${e}'. Please check your row style function.`);
}
}
return style;
}
public cellStyle(source: TimeseriesTableSource, index: number, row: TimeseriesRow, value: any): any {
let style: any = {};
if (index > 0) {
const styleInfo = source.stylesInfo[index - 1];
if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) {
public rowStyle(source: TimeseriesTableSource, row: TimeseriesRow, index: number): any {
let res = this.rowStyleCache[index];
if (!res) {
res = {};
if (this.rowStylesInfo.useRowStyleFunction && this.rowStylesInfo.rowStyleFunction) {
try {
const rowData = source.rowDataTemplate;
rowData.Timestamp = row[0];
source.header.forEach((headerInfo) => {
rowData[headerInfo.dataKey.name] = row[headerInfo.index];
});
style = styleInfo.cellStyleFunction(value, rowData, this.ctx);
if (!isObject(style)) {
throw new TypeError(`${style === null ? 'null' : typeof style} instead of style object`);
res = this.rowStylesInfo.rowStyleFunction(rowData, this.ctx);
if (!isObject(res)) {
throw new TypeError(`${res === null ? 'null' : typeof res} instead of style object`);
}
if (Array.isArray(style)) {
if (Array.isArray(res)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
style = {};
console.warn(`Cell style function for data key '${source.header[index - 1].dataKey.label}' in widget ` +
`'${this.ctx.widgetConfig.title}' returns '${e}'. Please check your cell style function.`);
res = {};
console.warn(`Row style function in widget ` +
`'${this.ctx.widgetConfig.title}' returns '${e}'. Please check your row style function.`);
}
}
this.rowStyleCache[index] = res;
}
return style;
}
public cellContent(source: TimeseriesTableSource, index: number, row: TimeseriesRow, value: any): SafeHtml {
if (index === 0) {
return row.formattedTs;
} else {
let content;
const contentInfo = source.contentsInfo[index - 1];
if (contentInfo.useCellContentFunction && contentInfo.cellContentFunction) {
try {
const rowData = source.rowDataTemplate;
rowData.Timestamp = row[0];
source.header.forEach((headerInfo) => {
rowData[headerInfo.dataKey.name] = row[headerInfo.index];
});
content = contentInfo.cellContentFunction(value, rowData, this.ctx);
} catch (e) {
content = '' + value;
return res;
}
public cellStyle(source: TimeseriesTableSource, index: number, row: TimeseriesRow, value: any, rowIndex: number): any {
const cacheIndex = rowIndex * (source.header.length + 1) + index;
let res = this.cellStyleCache[cacheIndex];
if (!res) {
res = {};
if (index > 0) {
const styleInfo = source.stylesInfo[index - 1];
if (styleInfo.useCellStyleFunction && styleInfo.cellStyleFunction) {
try {
const rowData = source.rowDataTemplate;
rowData.Timestamp = row[0];
source.header.forEach((headerInfo) => {
rowData[headerInfo.dataKey.name] = row[headerInfo.index];
});
res = styleInfo.cellStyleFunction(value, rowData, this.ctx);
if (!isObject(res)) {
throw new TypeError(`${res === null ? 'null' : typeof res} instead of style object`);
}
if (Array.isArray(res)) {
throw new TypeError(`Array instead of style object`);
}
} catch (e) {
res = {};
console.warn(`Cell style function for data key '${source.header[index - 1].dataKey.label}' in widget ` +
`'${this.ctx.widgetConfig.title}' returns '${e}'. Please check your cell style function.`);
}
}
} else {
const decimals = (contentInfo.decimals || contentInfo.decimals === 0) ? contentInfo.decimals : this.ctx.widgetConfig.decimals;
const units = contentInfo.units || this.ctx.widgetConfig.units;
content = this.ctx.utils.formatValue(value, decimals, units, true);
}
this.cellStyleCache[cacheIndex] = res;
}
return res;
}
if (!isDefined(content)) {
return '';
public cellContent(source: TimeseriesTableSource, index: number, row: TimeseriesRow, value: any, rowIndex: number): SafeHtml {
const cacheIndex = rowIndex * (source.header.length + 1) + index ;
let res = this.cellContentCache[cacheIndex];
if (isUndefined(res)) {
res = '';
if (index === 0) {
res = row.formattedTs;
} else {
content = this.utils.customTranslation(content, content);
switch (typeof content) {
case 'string':
return this.domSanitizer.bypassSecurityTrustHtml(content);
default:
return content;
let content;
const contentInfo = source.contentsInfo[index - 1];
if (contentInfo.useCellContentFunction && contentInfo.cellContentFunction) {
try {
const rowData = source.rowDataTemplate;
rowData.Timestamp = row[0];
source.header.forEach((headerInfo) => {
rowData[headerInfo.dataKey.name] = row[headerInfo.index];
});
content = contentInfo.cellContentFunction(value, rowData, this.ctx);
} catch (e) {
content = '' + value;
}
} else {
const decimals = (contentInfo.decimals || contentInfo.decimals === 0) ? contentInfo.decimals : this.ctx.widgetConfig.decimals;
const units = contentInfo.units || this.ctx.widgetConfig.units;
content = this.ctx.utils.formatValue(value, decimals, units, true);
}
if (isDefined(content)) {
content = this.utils.customTranslation(content, content);
switch (typeof content) {
case 'string':
res = this.domSanitizer.bypassSecurityTrustHtml(content);
break;
default:
res = content;
}
}
}
this.cellContentCache[cacheIndex] = res;
}
return res;
}
public onRowClick($event: Event, row: TimeseriesRow) {
@ -530,6 +552,13 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
private loadCurrentSourceRow() {
this.sources[this.sourceIndex].timeseriesDatasource.loadRows();
this.clearCache();
}
private clearCache() {
this.cellContentCache.length = 0;
this.cellStyleCache.length = 0;
this.rowStyleCache.length = 0;
}
}

Loading…
Cancel
Save