|
|
|
@ -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; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|