Browse Source

moved to new ui and fixed data bug

pull/14412/head
Maksym Tsymbarov 10 months ago
parent
commit
1e01b326e4
  1. 2
      application/src/main/data/json/system/widget_types/timeseries_table.json
  2. 25
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html
  3. 38
      ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts
  4. 88
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts
  5. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  6. 6
      ui-ngx/src/form.scss

2
application/src/main/data/json/system/widget_types/timeseries_table.json

@ -17,7 +17,7 @@
"latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings", "latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings",
"hasBasicMode": true, "hasBasicMode": true,
"basicModeDirective": "tb-timeseries-table-basic-config", "basicModeDirective": "tb-timeseries-table-basic-config",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":[]}],\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"enableSearch\":true,\"enableSelectColumnDisplay\":true,\"enableStickyHeader\":true,\"enableStickyAction\":true,\"showCellActionsMenu\":true,\"reserveSpaceForHiddenAction\":\"true\",\"showTimestamp\":true,\"dateFormat\":{\"format\":\"yyyy-MM-dd HH:mm:ss\"},\"displayPagination\":true,\"useEntityLabel\":false,\"defaultPageSize\":10,\"pageStepCount\":3,\"pageStepIncrement\":10,\"hideEmptyLines\":false,\"disableStickyHeader\":false,\"useRowStyleFunction\":false,\"rowStyleFunction\":\"\",\"tabSortKey\":\"timestamp\"},\"title\":\"Time series table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"configMode\":\"basic\",\"titleFont\":null,\"titleColor\":null,\"titleIcon\":null}" "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":[]}],\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"enableSearch\":true,\"enableSelectColumnDisplay\":true,\"enableStickyHeader\":true,\"enableStickyAction\":true,\"showCellActionsMenu\":true,\"reserveSpaceForHiddenAction\":\"true\",\"showTimestamp\":true,\"dateFormat\":{\"format\":\"yyyy-MM-dd HH:mm:ss\"},\"displayPagination\":true,\"useEntityLabel\":false,\"defaultPageSize\":10,\"pageStepCount\":3,\"pageStepIncrement\":10,\"hideEmptyLines\":false,\"disableStickyHeader\":false,\"useRowStyleFunction\":false,\"rowStyleFunction\":\"\",\"sortOrder\":{\"property\":\"createdTime\",\"direction\":\"ASC\"}},\"title\":\"Time series table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"configMode\":\"basic\",\"titleFont\":null,\"titleColor\":null,\"titleIcon\":null}"
}, },
"resources": [ "resources": [
{ {

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

@ -113,17 +113,24 @@
<div class="tb-form-panel"> <div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.table.table-tabs</div> <div class="tb-form-panel-title" translate>widgets.table.table-tabs</div>
<mat-slide-toggle class="mat-slide" formControlName="useEntityLabel"> <mat-slide-toggle class="mat-slide" formControlName="useEntityLabel">
{{ 'widgets.table.use-entity-label-tab-name' | translate }} {{ 'widgets.table.use-entity-label-header-title' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<div class="tb-form-row justify-between"> <div class="tb-form-row justify-between column-xs" formGroupName="sortOrder">
<div class="fixed-title-width" translate>widgets.table.sort-by</div> <div class="fixed-title-width" translate>widgets.table.sort-by</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic"> <div class="flex flex-1 flex-row justify-end gap-2 ">
<mat-select formControlName="tabSortKey" placeholder="{{ 'widget-config.set' | translate }}"> <mat-form-field class="flex-lt-lg medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-option [value]="TabSortKey.TIMESTAMP">{{ 'widgets.table.sort-timestamp-option' | translate }}</mat-option> <mat-select formControlName="property" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option [value]="TabSortKey.NAME_ASC">{{ 'widgets.table.sort-asc' | translate }}</mat-option> <mat-option [value]="entityFields.createdTime.value">{{ entityFields.createdTime.name | translate }}</mat-option>
<mat-option [value]="TabSortKey.NAME_DESC">{{ 'widgets.table.sort-desc' | translate }}</mat-option> <mat-option [value]="entityFields.name.value">{{ entityFields.name.name | translate }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="flex-lt-lg medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="direction" placeholder="{{ 'widget-config.set' | translate }}">
<mat-option [value]="Direction.ASC">{{ 'widgets.table.sort-asc' | translate }}</mat-option>
<mat-option [value]="Direction.DESC">{{ 'widgets.table.sort-desc' | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div> </div>
</div> </div>
<div class="tb-form-panel tb-slide-toggle"> <div class="tb-form-panel tb-slide-toggle">

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

@ -20,7 +20,8 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { buildPageStepSizeValues } from '@home/components/widget/lib/table-widget.models'; import { buildPageStepSizeValues } from '@home/components/widget/lib/table-widget.models';
import { TabSortKey } from '@app/modules/home/components/widget/lib/timeseries-table-widget.component' import { Direction } from '@shared/models/page/sort-order';
import { entityFields } from '@shared/models/entity.models';
@Component({ @Component({
selector: 'tb-timeseries-table-widget-settings', selector: 'tb-timeseries-table-widget-settings',
@ -29,7 +30,8 @@ import { TabSortKey } from '@app/modules/home/components/widget/lib/timeseries-t
}) })
export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsComponent { export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsComponent {
TabSortKey = TabSortKey; entityFields = entityFields;
Direction = Direction;
timeseriesTableWidgetSettingsForm: UntypedFormGroup; timeseriesTableWidgetSettingsForm: UntypedFormGroup;
pageStepSizeValues = []; pageStepSizeValues = [];
@ -44,6 +46,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
} }
protected defaultSettings(): WidgetSettings { protected defaultSettings(): WidgetSettings {
console.log("default")
return { return {
enableSearch: true, enableSearch: true,
enableSelectColumnDisplay: true, enableSelectColumnDisplay: true,
@ -62,14 +65,21 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
disableStickyHeader: false, disableStickyHeader: false,
useRowStyleFunction: false, useRowStyleFunction: false,
rowStyleFunction: '', rowStyleFunction: '',
tabSortKey: TabSortKey.TIMESTAMP sortOrder: {
property: this.entityFields.name.keyName,
direction: Direction.ASC
}
}; };
} }
protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { protected prepareInputSettings(settings: WidgetSettings): WidgetSettings {
settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize; settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize;
settings.tabSortKey = settings.tabSortKey ?? TabSortKey.TIMESTAMP; settings.sortOrder = {
property: settings.sortOrder?.property || this.entityFields.name.keyName,
direction: settings.sortOrder?.direction || Direction.ASC
};
this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement); this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement);
console.log("input",settings)
return settings; return settings;
} }
@ -99,7 +109,16 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
disableStickyHeader: [settings.disableStickyHeader, []], disableStickyHeader: [settings.disableStickyHeader, []],
useRowStyleFunction: [settings.useRowStyleFunction, []], useRowStyleFunction: [settings.useRowStyleFunction, []],
rowStyleFunction: [settings.rowStyleFunction, [Validators.required]], rowStyleFunction: [settings.rowStyleFunction, [Validators.required]],
tabSortKey: [settings.tabSortKey, []], sortOrder: this.fb.group({
property: [
settings.sortOrder.property,
Validators.required
],
direction: [
settings.sortOrder.direction,
Validators.required
]
})
}); });
} }
@ -107,6 +126,15 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
return ['useRowStyleFunction', 'displayPagination', 'pageStepCount', 'pageStepIncrement']; return ['useRowStyleFunction', 'displayPagination', 'pageStepCount', 'pageStepIncrement'];
} }
protected prepareOutputSettings(settings: WidgetSettings): WidgetSettings {
settings.sortOrder = {
property: settings.sortOrder?.property || this.entityFields.name.keyName,
direction: settings.sortOrder?.direction || Direction.ASC
};
console.log("output",settings)
return settings;
}
protected updateValidators(emitEvent: boolean, trigger: string) { protected updateValidators(emitEvent: boolean, trigger: string) {
if (trigger === 'pageStepCount' || trigger === 'pageStepIncrement') { if (trigger === 'pageStepCount' || trigger === 'pageStepIncrement') {
this.timeseriesTableWidgetSettingsForm.get('defaultPageSize').reset(); this.timeseriesTableWidgetSettingsForm.get('defaultPageSize').reset();

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

@ -106,19 +106,14 @@ import { ComponentPortal } from '@angular/cdk/portal';
import { FormBuilder } from '@angular/forms'; import { FormBuilder } from '@angular/forms';
import { DEFAULT_OVERLAY_POSITIONS } from '@shared/models/overlay.models'; import { DEFAULT_OVERLAY_POSITIONS } from '@shared/models/overlay.models';
import { DateFormatSettings, ValueFormatProcessor } from '@shared/models/widget-settings.models'; import { DateFormatSettings, ValueFormatProcessor } from '@shared/models/widget-settings.models';
import { entityFields } from '@shared/models/entity.models';
export enum TabSortKey {
NAME_ASC = 'NAME_ASC',
NAME_DESC = 'NAME_DESC',
TIMESTAMP = 'timestamp'
}
export interface TimeseriesTableWidgetSettings extends TableWidgetSettings { export interface TimeseriesTableWidgetSettings extends TableWidgetSettings {
showTimestamp: boolean; showTimestamp: boolean;
showMilliseconds: boolean; showMilliseconds: boolean;
hideEmptyLines: boolean; hideEmptyLines: boolean;
dateFormat: DateFormatSettings; dateFormat: DateFormatSettings;
tabSortKey: TabSortKey; sortOrder: SortOrder;
} }
interface TimeseriesWidgetLatestDataKeySettings extends TableWidgetDataKeySettings { interface TimeseriesWidgetLatestDataKeySettings extends TableWidgetDataKeySettings {
@ -405,7 +400,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
return entityLabelCache.get(source.entityId); return entityLabelCache.get(source.entityId);
} }
const value = this.useEntityLabel const value = this.useEntityLabel
? (source.entityLabel || source.entityName) ? (source.entityLabel || source.entityName)
: source.entityName; : source.entityName;
@ -414,19 +409,78 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
return translated; return translated;
} }
private sortDatasources(source: Datasource[], entityLabelCache:Map<string,string>): Datasource[] { private sortDatasources(source: Datasource[], entityLabelCache: Map<string, string>): Datasource[] {
const property = this.settings?.sortOrder?.property;
const direction = this.settings?.sortOrder?.direction;
const isAsc = direction === Direction.ASC;
let sortedSource = [...source];
source.forEach(ds => this.getTabLabel(ds, entityLabelCache)); source.forEach(ds => this.getTabLabel(ds, entityLabelCache));
if (this.settings.tabSortKey === TabSortKey.TIMESTAMP) { if (property === entityFields.name.keyName) {
return source; const collator = new Intl.Collator(undefined, {
sensitivity: "variant",
numeric: true,
ignorePunctuation: false
});
sortedSource.sort((a, b) => {
const valueA = entityLabelCache.get(a.entityId) || '';
const valueB = entityLabelCache.get(b.entityId) || '';
return isAsc
? collator.compare(valueA, valueB)
: collator.compare(valueB, valueA);
});
} else if (property === entityFields.createdTime.keyName) {
if (!isAsc) {
sortedSource.reverse();
}
} }
return source.sort((a, b) => { this.reorderDataArrays(source, sortedSource);
const valueA = entityLabelCache.get(a.entityId); return sortedSource;
const valueB = entityLabelCache.get(b.entityId); }
return this.settings.tabSortKey === TabSortKey.NAME_ASC
? valueA.localeCompare(valueB) private reorderDataArrays(originalOrder: Datasource[], newOrder: Datasource[]): void {
: valueB.localeCompare(valueA); const indexMap = new Map<number, number>();
originalOrder.forEach((ds, oldIndex) => {
const newIndex = newOrder.findIndex(newDs => newDs.entityId === ds.entityId);
indexMap.set(oldIndex, newIndex);
}); });
const newData: Array<DatasourceData> = [];
originalOrder.forEach((ds, oldIndex) => {
const dataKeys = ds.dataKeys;
const startIdx = oldIndex * dataKeys.length;
const endIdx = startIdx + dataKeys.length;
const datasourceData = this.data.slice(startIdx, endIdx);
const newIndex = indexMap.get(oldIndex);
const newStartIdx = newIndex * dataKeys.length;
datasourceData.forEach((data, i) => {
newData[newStartIdx + i] = data;
});
});
this.data = newData;
if (this.latestData && this.latestData.length > 0) {
const newLatestData: Array<DatasourceData> = [];
originalOrder.forEach((ds, oldIndex) => {
const latestDataKeys = ds.latestDataKeys || [];
const startIdx = oldIndex * latestDataKeys.length;
const endIdx = startIdx + latestDataKeys.length;
const datasourceLatestData = this.latestData.slice(startIdx, endIdx);
const newIndex = indexMap.get(oldIndex);
const newStartIdx = newIndex * latestDataKeys.length;
datasourceLatestData.forEach((data, i) => {
newLatestData[newStartIdx + i] = data;
});
});
this.latestData = newLatestData;
}
} }
private updateDatasources() { private updateDatasources() {

6
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -9482,7 +9482,7 @@
"page-step-increment": "Step increment", "page-step-increment": "Step increment",
"page-step-count-format-message": "Should be an integer value, in the range from 1 to 100.", "page-step-count-format-message": "Should be an integer value, in the range from 1 to 100.",
"page-step-increment-format-message": "Should be an integer value, greater or equal to 1.", "page-step-increment-format-message": "Should be an integer value, greater or equal to 1.",
"use-entity-label-tab-name": "Use entity label in tab name", "use-entity-label-header-title": "Use entity label in header title",
"hide-empty-lines": "Hide empty lines", "hide-empty-lines": "Hide empty lines",
"row-style": "Row style", "row-style": "Row style",
"use-row-style-function": "Use row style function", "use-row-style-function": "Use row style function",
@ -9538,8 +9538,8 @@
"show-cell-actions-menu-mobile": "Show cell actions dropdown menu in mobile mode", "show-cell-actions-menu-mobile": "Show cell actions dropdown menu in mobile mode",
"disable-sorting": "Disable sorting", "disable-sorting": "Disable sorting",
"sort-by": "Sort tabs by", "sort-by": "Sort tabs by",
"sort-asc": "Name Ascending", "sort-asc": "Ascending",
"sort-desc": "Name Descending", "sort-desc": "Descending",
"sort-timestamp-option": "Created time" "sort-timestamp-option": "Created time"
}, },
"latest-chart": { "latest-chart": {

6
ui-ngx/src/form.scss

@ -257,6 +257,12 @@
flex: 1; flex: 1;
} }
} }
&.flex-lt-lg {
@media #{$mat-lt-lg} {
width: auto;
flex: 1;
}
}
} }
.fixed-title-width { .fixed-title-width {
min-width: 200px; min-width: 200px;

Loading…
Cancel
Save