From 1e01b326e42a79eb450a8786ff9ce6d3cd9f67c8 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Mon, 24 Nov 2025 14:52:37 +0200 Subject: [PATCH 1/6] moved to new ui and fixed data bug --- .../system/widget_types/timeseries_table.json | 2 +- ...eries-table-widget-settings.component.html | 25 ++++-- ...eseries-table-widget-settings.component.ts | 38 ++++++-- .../lib/timeseries-table-widget.component.ts | 88 +++++++++++++++---- .../assets/locale/locale.constant-en_US.json | 6 +- ui-ngx/src/form.scss | 6 ++ 6 files changed, 130 insertions(+), 35 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/timeseries_table.json b/application/src/main/data/json/system/widget_types/timeseries_table.json index 625f7a1e7d..0283899134 100644 --- a/application/src/main/data/json/system/widget_types/timeseries_table.json +++ b/application/src/main/data/json/system/widget_types/timeseries_table.json @@ -17,7 +17,7 @@ "latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings", "hasBasicMode": true, "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": [ { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index f236dd1acd..ae07674162 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -113,17 +113,24 @@
widgets.table.table-tabs
- {{ 'widgets.table.use-entity-label-tab-name' | translate }} + {{ 'widgets.table.use-entity-label-header-title' | translate }} -
+
widgets.table.sort-by
- - - {{ 'widgets.table.sort-timestamp-option' | translate }} - {{ 'widgets.table.sort-asc' | translate }} - {{ 'widgets.table.sort-desc' | translate }} - - +
+ + + {{ entityFields.createdTime.name | translate }} + {{ entityFields.name.name | translate }} + + + + + {{ 'widgets.table.sort-asc' | translate }} + {{ 'widgets.table.sort-desc' | translate }} + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index ccbb582679..95a9eb8014 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/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 { AppState } from '@core/core.state'; 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({ 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 { - TabSortKey = TabSortKey; + entityFields = entityFields; + Direction = Direction; timeseriesTableWidgetSettingsForm: UntypedFormGroup; pageStepSizeValues = []; @@ -44,6 +46,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon } protected defaultSettings(): WidgetSettings { + console.log("default") return { enableSearch: true, enableSelectColumnDisplay: true, @@ -62,14 +65,21 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon disableStickyHeader: false, useRowStyleFunction: false, rowStyleFunction: '', - tabSortKey: TabSortKey.TIMESTAMP + sortOrder: { + property: this.entityFields.name.keyName, + direction: Direction.ASC + } }; } protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { 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); + console.log("input",settings) return settings; } @@ -99,7 +109,16 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon disableStickyHeader: [settings.disableStickyHeader, []], useRowStyleFunction: [settings.useRowStyleFunction, []], 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']; } + 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) { if (trigger === 'pageStepCount' || trigger === 'pageStepIncrement') { this.timeseriesTableWidgetSettingsForm.get('defaultPageSize').reset(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index dbd4905299..d6c73d7f82 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/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 { DEFAULT_OVERLAY_POSITIONS } from '@shared/models/overlay.models'; import { DateFormatSettings, ValueFormatProcessor } from '@shared/models/widget-settings.models'; - -export enum TabSortKey { - NAME_ASC = 'NAME_ASC', - NAME_DESC = 'NAME_DESC', - TIMESTAMP = 'timestamp' -} +import { entityFields } from '@shared/models/entity.models'; export interface TimeseriesTableWidgetSettings extends TableWidgetSettings { showTimestamp: boolean; showMilliseconds: boolean; hideEmptyLines: boolean; dateFormat: DateFormatSettings; - tabSortKey: TabSortKey; + sortOrder: SortOrder; } interface TimeseriesWidgetLatestDataKeySettings extends TableWidgetDataKeySettings { @@ -405,7 +400,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI return entityLabelCache.get(source.entityId); } - const value = this.useEntityLabel + const value = this.useEntityLabel ? (source.entityLabel || source.entityName) : source.entityName; @@ -414,19 +409,78 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI return translated; } - private sortDatasources(source: Datasource[], entityLabelCache:Map): Datasource[] { + private sortDatasources(source: Datasource[], entityLabelCache: Map): 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)); - if (this.settings.tabSortKey === TabSortKey.TIMESTAMP) { - return source; + if (property === entityFields.name.keyName) { + 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) => { - const valueA = entityLabelCache.get(a.entityId); - const valueB = entityLabelCache.get(b.entityId); - return this.settings.tabSortKey === TabSortKey.NAME_ASC - ? valueA.localeCompare(valueB) - : valueB.localeCompare(valueA); + this.reorderDataArrays(source, sortedSource); + return sortedSource; + } + + private reorderDataArrays(originalOrder: Datasource[], newOrder: Datasource[]): void { + const indexMap = new Map(); + originalOrder.forEach((ds, oldIndex) => { + const newIndex = newOrder.findIndex(newDs => newDs.entityId === ds.entityId); + indexMap.set(oldIndex, newIndex); }); + + const newData: Array = []; + 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 = []; + 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() { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 538b3a8352..9850ec73d7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -9482,7 +9482,7 @@ "page-step-increment": "Step increment", "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.", - "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", "row-style": "Row style", "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", "disable-sorting": "Disable sorting", "sort-by": "Sort tabs by", - "sort-asc": "Name Ascending", - "sort-desc": "Name Descending", + "sort-asc": "Ascending", + "sort-desc": "Descending", "sort-timestamp-option": "Created time" }, "latest-chart": { diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index af166b406d..b8e269c14e 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -257,6 +257,12 @@ flex: 1; } } + &.flex-lt-lg { + @media #{$mat-lt-lg} { + width: auto; + flex: 1; + } + } } .fixed-title-width { min-width: 200px; From 0e8b99c067a5a8d2c833ab2717a6c77be00ddc86 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Tue, 25 Nov 2025 16:00:37 +0200 Subject: [PATCH 2/6] moved sorting of datasources --- .../system/widget_types/timeseries_table.json | 2 +- ...eries-table-widget-settings.component.html | 6 +- ...eseries-table-widget-settings.component.ts | 13 ++-- .../lib/timeseries-table-widget.component.ts | 64 +++---------------- .../assets/locale/locale.constant-en_US.json | 6 +- 5 files changed, 21 insertions(+), 70 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/timeseries_table.json b/application/src/main/data/json/system/widget_types/timeseries_table.json index 0283899134..543d189f70 100644 --- a/application/src/main/data/json/system/widget_types/timeseries_table.json +++ b/application/src/main/data/json/system/widget_types/timeseries_table.json @@ -17,7 +17,7 @@ "latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings", "hasBasicMode": true, "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\":\"\",\"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}" + "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\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"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\":\"DESC\"}},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"advanced\"}" }, "resources": [ { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index ae07674162..bd223238a8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -113,7 +113,7 @@
widgets.table.table-tabs
- {{ 'widgets.table.use-entity-label-header-title' | translate }} + {{ 'widgets.table.use-entity-label-tab-name' | translate }}
widgets.table.sort-by
@@ -126,8 +126,8 @@ - {{ 'widgets.table.sort-asc' | translate }} - {{ 'widgets.table.sort-desc' | translate }} + {{ 'common.sort-asc' | translate }} + {{ 'common.sort-desc' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index 95a9eb8014..d501d581c9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts @@ -46,7 +46,6 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon } protected defaultSettings(): WidgetSettings { - console.log("default") return { enableSearch: true, enableSelectColumnDisplay: true, @@ -67,7 +66,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon rowStyleFunction: '', sortOrder: { property: this.entityFields.name.keyName, - direction: Direction.ASC + direction: Direction.DESC } }; } @@ -75,11 +74,10 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { settings.pageStepIncrement = settings.pageStepIncrement ?? settings.defaultPageSize; settings.sortOrder = { - property: settings.sortOrder?.property || this.entityFields.name.keyName, - direction: settings.sortOrder?.direction || Direction.ASC + property: settings.sortOrder?.property || this.entityFields.createdTime.keyName, + direction: settings.sortOrder?.direction || Direction.DESC }; this.pageStepSizeValues = buildPageStepSizeValues(settings.pageStepCount, settings.pageStepIncrement); - console.log("input",settings) return settings; } @@ -128,10 +126,9 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon protected prepareOutputSettings(settings: WidgetSettings): WidgetSettings { settings.sortOrder = { - property: settings.sortOrder?.property || this.entityFields.name.keyName, - direction: settings.sortOrder?.direction || Direction.ASC + property: settings.sortOrder?.property || this.entityFields.createdTime.keyName, + direction: settings.sortOrder?.direction || Direction.DESC }; - console.log("output",settings) return settings; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index d6c73d7f82..5b18fac9c0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -409,13 +409,10 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI return translated; } - private sortDatasources(source: Datasource[], entityLabelCache: Map): Datasource[] { + private sortDatasources(source: TimeseriesTableSource[], entityLabelCache: Map) { 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)); if (property === entityFields.name.keyName) { const collator = new Intl.Collator(undefined, { @@ -424,63 +421,19 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI ignorePunctuation: false }); - sortedSource.sort((a, b) => { - const valueA = entityLabelCache.get(a.entityId) || ''; - const valueB = entityLabelCache.get(b.entityId) || ''; + source.sort((a, b) => { + const valueA = entityLabelCache.get(a.datasource.entityId) || ''; + const valueB = entityLabelCache.get(a.datasource.entityId) || ''; return isAsc ? collator.compare(valueA, valueB) : collator.compare(valueB, valueA); }); } else if (property === entityFields.createdTime.keyName) { - if (!isAsc) { - sortedSource.reverse(); + if (isAsc) { + source.reverse(); } } - this.reorderDataArrays(source, sortedSource); - return sortedSource; - } - - private reorderDataArrays(originalOrder: Datasource[], newOrder: Datasource[]): void { - const indexMap = new Map(); - originalOrder.forEach((ds, oldIndex) => { - const newIndex = newOrder.findIndex(newDs => newDs.entityId === ds.entityId); - indexMap.set(oldIndex, newIndex); - }); - - const newData: Array = []; - 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 = []; - 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() { @@ -491,8 +444,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI const entityLabelCache = new Map(); const pageSize = this.displayPagination ? this.defaultPageSize : Number.POSITIVE_INFINITY; if (this.datasources) { - const sortedDatasources = this.sortDatasources(this.datasources, entityLabelCache); - for (const datasource of sortedDatasources) { + this.datasources.forEach(ds => this.getTabLabel(ds, entityLabelCache)); + for (const datasource of this.datasources) { const sortOrder: SortOrder = sortOrderFromString(this.defaultSortOrder); const source = {} as TimeseriesTableSource; source.header = this.prepareHeader(datasource); @@ -529,6 +482,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } } if (this.sources.length) { + this.sortDatasources(this.sources, entityLabelCache); this.sources.forEach((source, index) => { this.prepareDisplayedColumn(index); source.displayedColumns = this.displayedColumns[index].filter(value => value.display).map(value => value.def); diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 9850ec73d7..5a0be16baf 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1639,6 +1639,8 @@ "documentation": "Documentation", "time-left": "{{time}} left", "output": "Output", + "sort-asc": "Ascending", + "sort-desc": "Descending", "suffix": { "s": "s", "ms": "ms" @@ -9482,7 +9484,7 @@ "page-step-increment": "Step increment", "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.", - "use-entity-label-header-title": "Use entity label in header title", + "use-entity-label-tab-name": "Use entity label in tab name", "hide-empty-lines": "Hide empty lines", "row-style": "Row style", "use-row-style-function": "Use row style function", @@ -9538,8 +9540,6 @@ "show-cell-actions-menu-mobile": "Show cell actions dropdown menu in mobile mode", "disable-sorting": "Disable sorting", "sort-by": "Sort tabs by", - "sort-asc": "Ascending", - "sort-desc": "Descending", "sort-timestamp-option": "Created time" }, "latest-chart": { From 8fd3986ee9c846caf7035ed017ee652af8e147f4 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Tue, 25 Nov 2025 16:08:30 +0200 Subject: [PATCH 3/6] Update timeseries_table.json --- .../main/data/json/system/widget_types/timeseries_table.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_types/timeseries_table.json b/application/src/main/data/json/system/widget_types/timeseries_table.json index 543d189f70..24443cfecf 100644 --- a/application/src/main/data/json/system/widget_types/timeseries_table.json +++ b/application/src/main/data/json/system/widget_types/timeseries_table.json @@ -17,7 +17,7 @@ "latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings", "hasBasicMode": true, "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\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"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\":\"DESC\"}},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"advanced\"}" + "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\":\"DESC\"}},\"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": [ { From c4f7b385db756aa6c1c7e8b5b26f84e99599e114 Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Tue, 25 Nov 2025 16:17:10 +0200 Subject: [PATCH 4/6] fixed typo in getting translation for sort value --- .../components/widget/lib/timeseries-table-widget.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 5b18fac9c0..47322aaed1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -423,7 +423,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI source.sort((a, b) => { const valueA = entityLabelCache.get(a.datasource.entityId) || ''; - const valueB = entityLabelCache.get(a.datasource.entityId) || ''; + const valueB = entityLabelCache.get(b.datasource.entityId) || ''; return isAsc ? collator.compare(valueA, valueB) From 53598ac49c1c1a4a3a0eb3cabf676a68307f2ebc Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Tue, 25 Nov 2025 16:43:37 +0200 Subject: [PATCH 5/6] updated api usage dashboard --- ...eseries-table-widget-settings.component.ts | 2 +- .../lib/timeseries-table-widget.component.ts | 22 ++++++------------- ui-ngx/src/assets/dashboard/api_usage.json | 5 ++++- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index d501d581c9..3911506be7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts @@ -65,7 +65,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon useRowStyleFunction: false, rowStyleFunction: '', sortOrder: { - property: this.entityFields.name.keyName, + property: this.entityFields.createdTime.keyName, direction: Direction.DESC } }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 47322aaed1..282fab9a3e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -395,21 +395,15 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.updateDatasources(); } - private getTabLabel(source: Datasource, entityLabelCache:Map):string { - if (entityLabelCache.has(source.entityId)) { - return entityLabelCache.get(source.entityId); - } - + private getTabLabel(source: Datasource):string { const value = this.useEntityLabel ? (source.entityLabel || source.entityName) : source.entityName; - const translated = this.utils.customTranslation(value); - entityLabelCache.set(source.entityId, translated); - return translated; + return this.utils.customTranslation(value); } - private sortDatasources(source: TimeseriesTableSource[], entityLabelCache: Map) { + private sortDatasources(source: TimeseriesTableSource[]) { const property = this.settings?.sortOrder?.property; const direction = this.settings?.sortOrder?.direction; const isAsc = direction === Direction.ASC; @@ -422,8 +416,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI }); source.sort((a, b) => { - const valueA = entityLabelCache.get(a.datasource.entityId) || ''; - const valueB = entityLabelCache.get(b.datasource.entityId) || ''; + const valueA = a.displayName || ''; + const valueB = b.displayName || ''; return isAsc ? collator.compare(valueA, valueB) @@ -441,10 +435,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.sourceIndex = 0; let keyOffset = 0; let latestKeyOffset = 0; - const entityLabelCache = new Map(); const pageSize = this.displayPagination ? this.defaultPageSize : Number.POSITIVE_INFINITY; if (this.datasources) { - this.datasources.forEach(ds => this.getTabLabel(ds, entityLabelCache)); for (const datasource of this.datasources) { const sortOrder: SortOrder = sortOrderFromString(this.defaultSortOrder); const source = {} as TimeseriesTableSource; @@ -462,7 +454,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI source.pageLink = new PageLink(pageSize, 0, null, sortOrder); source.rowDataTemplate = {}; source.rowDataTemplate.Timestamp = null; - source.displayName = entityLabelCache.get(datasource.entityId); + source.displayName = this.getTabLabel(datasource); if (this.showTimestamp) { source.displayedColumns.push('0'); } @@ -482,7 +474,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } } if (this.sources.length) { - this.sortDatasources(this.sources, entityLabelCache); + this.sortDatasources(this.sources); this.sources.forEach((source, index) => { this.prepareDisplayedColumn(index); source.displayedColumns = this.displayedColumns[index].filter(value => value.display).map(value => value.def); diff --git a/ui-ngx/src/assets/dashboard/api_usage.json b/ui-ngx/src/assets/dashboard/api_usage.json index 994b431ade..e45e9a59fa 100644 --- a/ui-ngx/src/assets/dashboard/api_usage.json +++ b/ui-ngx/src/assets/dashboard/api_usage.json @@ -99,7 +99,10 @@ "showTimestamp": true, "displayPagination": true, "defaultPageSize": 10, - "tabSortKey": "NAME_ASC" + "sortOrder": { + "property": "createdTime", + "direction": "DESC" + } }, "title": "{i18n:api-usage.exceptions}", "dropShadow": true, From 7b1bee4380a55ed2ad634c9e7ef58f26a04dc169 Mon Sep 17 00:00:00 2001 From: Vladyslav Prykhodko Date: Tue, 25 Nov 2025 18:26:17 +0200 Subject: [PATCH 6/6] Update api_usage.json --- ui-ngx/src/assets/dashboard/api_usage.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/assets/dashboard/api_usage.json b/ui-ngx/src/assets/dashboard/api_usage.json index e45e9a59fa..bf3fd220be 100644 --- a/ui-ngx/src/assets/dashboard/api_usage.json +++ b/ui-ngx/src/assets/dashboard/api_usage.json @@ -100,8 +100,8 @@ "displayPagination": true, "defaultPageSize": 10, "sortOrder": { - "property": "createdTime", - "direction": "DESC" + "property": "name", + "direction": "ASC" } }, "title": "{i18n:api-usage.exceptions}",