From d1e7f48c4c6533a3b7a48de1da74792ac44440bd Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 16 Jun 2025 15:09:03 +0300 Subject: [PATCH] UI: Add deepClean widget config --- .../src/app/core/api/widget-subscription.ts | 6 ++-- .../core/services/dashboard-utils.service.ts | 5 +++- ui-ngx/src/app/core/utils.ts | 30 ++++++++++++++++++- .../alias/entity-aliases-dialog.component.ts | 4 +-- .../dashboard-page.component.ts | 8 ++--- .../dashboard-settings-dialog.component.ts | 8 ++--- .../alarm/alarms-table-widget.component.ts | 12 ++------ .../entity/entities-table-widget.component.ts | 2 +- .../widget/lib/table-widget.models.ts | 4 +-- .../src/app/shared/models/dashboard.models.ts | 4 +-- 10 files changed, 53 insertions(+), 30 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index f1ff771f88..6aad086489 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -1497,9 +1497,9 @@ export class WidgetSubscription implements IWidgetSubscription { private entityDataToDatasourceData(datasource: Datasource, data: Array): Array { let datasourceDataArray: Array = []; datasourceDataArray = datasourceDataArray.concat(datasource.dataKeys.map((dataKey, keyIndex) => { - dataKey.hidden = !!dataKey.settings.hideDataByDefault; - dataKey.inLegend = dataKey.settings.showInLegend || - (isUndefined(dataKey.settings.showInLegend) && !dataKey.settings.removeFromLegend); + dataKey.hidden = !!dataKey.settings?.hideDataByDefault; + dataKey.inLegend = dataKey.settings?.showInLegend || + (isUndefined(dataKey.settings?.showInLegend) && !dataKey.settings?.removeFromLegend); dataKey.label = this.ctx.utils.customTranslation(dataKey.label, dataKey.label); const datasourceData: DatasourceData = { datasource, diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 1511840c57..fe6dcdab85 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -78,7 +78,10 @@ export class DashboardUtilsService { public validateAndUpdateDashboard(dashboard: Dashboard): Dashboard { if (!dashboard.configuration) { - dashboard.configuration = {}; + dashboard.configuration = { + entityAliases: {}, + filters: {}, + }; } if (isUndefined(dashboard.configuration.widgets)) { dashboard.configuration.widgets = {}; diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 353727e006..d0bd9ae484 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -27,7 +27,8 @@ import { serverErrorCodesTranslations } from '@shared/models/constants'; import { SubscriptionEntityInfo } from '@core/api/widget-api.models'; import { CompiledTbFunction, - compileTbFunction, GenericFunction, + compileTbFunction, + GenericFunction, isNotEmptyTbFunction, TbFunction } from '@shared/models/js-function.models'; @@ -773,6 +774,33 @@ export function deepTrim(obj: T): T { }, (Array.isArray(obj) ? [] : {}) as T); } +export function deepClean | any[]>(obj: T, { + cleanKeys = [] +} = {}): T { + return _.transform(obj, (result, value, key) => { + if (cleanKeys.includes(key)) { + return; + } + if (Array.isArray(value) || isLiteralObject(value)) { + value = deepClean(value, {cleanKeys}); + } + if(isLiteralObject(value) && isEmpty(value)) { + return; + } + if (Array.isArray(value) && !value.length) { + return; + } + if (value === undefined || value === null || value === '' || Number.isNaN(value)) { + return; + } + + if (Array.isArray(result)) { + return result.push(value); + } + result[key] = value; + }); +} + export function generateSecret(length?: number): string { if (isUndefined(length) || length == null) { length = 1; diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts index f7bb87455a..fa9f0a718a 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts @@ -37,7 +37,7 @@ import { AliasEntityType, EntityType } from '@shared/models/entity-type.models'; import { TranslateService } from '@ngx-translate/core'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { DialogService } from '@core/services/dialog.service'; -import { deepClone, isUndefined } from '@core/utils'; +import { deepClean, deepClone, isUndefined } from '@core/utils'; import { EntityAliasDialogComponent, EntityAliasDialogData } from './entity-alias-dialog.component'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -263,7 +263,7 @@ export class EntityAliasesDialogComponent extends DialogComponent { if (err.status === HttpStatusCode.Conflict) { @@ -1409,8 +1409,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC saveWidget() { this.editWidgetComponent.widgetFormGroup.markAsPristine(); - const widget = deepClone(this.editingWidget); - const widgetLayout = deepClone(this.editingWidgetLayout); + const widget = deepClean(deepClone(this.editingWidget), {cleanKeys: ['_hash']}); + const widgetLayout = deepClean(deepClone(this.editingWidgetLayout)); const id = this.editingWidgetOriginal.id; this.dashboardConfiguration.widgets[id] = widget; this.editingWidgetOriginal = widget; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts index cfcafcb902..5780753759 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Inject, OnDestroy, OnInit, SkipSelf } from '@angular/core'; +import { Component, Inject, OnDestroy, SkipSelf } from '@angular/core'; import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -33,7 +33,7 @@ import { viewFormatTypes, viewFormatTypeTranslationMap } from '@app/shared/models/dashboard.models'; -import { isDefined, isUndefined } from '@core/utils'; +import { deepClean, deepTrim, isDefined, isUndefined } from '@core/utils'; import { StatesControllerService } from './states/states-controller.service'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; import { merge, Subject } from 'rxjs'; @@ -295,10 +295,10 @@ export class DashboardSettingsDialogComponent extends DialogComponent { const dataKey: EntityColumn = deepClone(alarmDataKey) as EntityColumn; - const keySettings: TableWidgetDataKeySettings = dataKey.settings; + const keySettings: TableWidgetDataKeySettings = dataKey.settings ?? {}; dataKey.entityKey = dataKeyToEntityKey(alarmDataKey); dataKey.label = this.utils.customTranslation(dataKey.label, dataKey.label); dataKey.title = getHeaderTitle(dataKey, keySettings, this.utils); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts index 82537384a1..f0f8903c38 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts @@ -461,7 +461,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni } dataKeys.push(dataKey); - const keySettings: TableWidgetDataKeySettings = dataKey.settings; + const keySettings: TableWidgetDataKeySettings = dataKey.settings ?? {}; dataKey.label = this.utils.customTranslation(dataKey.label, dataKey.label); dataKey.title = getHeaderTitle(dataKey, keySettings, this.utils); dataKey.def = 'def' + this.columns.length; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index 7e91a2f043..af852ca588 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -555,8 +555,8 @@ export function constructTableCssString(widgetConfig: WidgetConfig): string { return cssString; } -export function getHeaderTitle(dataKey: DataKey, keySettings: TableWidgetDataKeySettings, utils: UtilsService) { - if (isDefined(keySettings.customTitle) && isNotEmptyStr(keySettings.customTitle)) { +export function getHeaderTitle(dataKey: DataKey, keySettings: TableWidgetDataKeySettings | undefined, utils: UtilsService) { + if (isNotEmptyStr(keySettings?.customTitle)) { return utils.customTranslation(keySettings.customTitle, keySettings.customTitle); } return dataKey.label; diff --git a/ui-ngx/src/app/shared/models/dashboard.models.ts b/ui-ngx/src/app/shared/models/dashboard.models.ts index 8fe92f1b80..75e8de8dbb 100644 --- a/ui-ngx/src/app/shared/models/dashboard.models.ts +++ b/ui-ngx/src/app/shared/models/dashboard.models.ts @@ -186,8 +186,8 @@ export interface DashboardConfiguration { settings?: DashboardSettings; widgets?: {[id: string]: Widget } | Widget[]; states?: {[id: string]: DashboardState }; - entityAliases?: EntityAliases; - filters?: Filters; + entityAliases: EntityAliases; + filters: Filters; [key: string]: any; }