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 ecb3e65c61..b743126fdc 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -38,6 +38,7 @@ import { import { deepClone, isDefined, isDefinedAndNotNull, isNotEmptyStr, isString, isUndefined } from '@core/utils'; import { Datasource, + datasourcesHasAggregation, datasourcesHasOnlyComparisonAggregation, DatasourceType, defaultLegendConfig, @@ -49,7 +50,8 @@ import { WidgetConfigMode, WidgetSize, widgetType, - WidgetTypeDescriptor + WidgetTypeDescriptor, + widgetTypeHasTimewindow } from '@app/shared/models/widget.models'; import { EntityType } from '@shared/models/entity-type.models'; import { AliasFilterType, EntityAlias, EntityAliasFilter } from '@app/shared/models/alias.models'; @@ -295,8 +297,11 @@ export class DashboardUtilsService { widgetConfig.datasources = this.validateAndUpdateDatasources(widgetConfig.datasources); if (type === widgetType.latest) { const onlyHistoryTimewindow = datasourcesHasOnlyComparisonAggregation(widgetConfig.datasources); - widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, - onlyHistoryTimewindow, this.timeService, false); + const aggregationEnabledForKeys = datasourcesHasAggregation(widgetConfig.datasources); + if (aggregationEnabledForKeys) { + widgetConfig.timewindow = initModelFromDefaultTimewindow(widgetConfig.timewindow, true, + onlyHistoryTimewindow, this.timeService, false); + } } else if (type === widgetType.rpc) { if (widgetConfig.targetDeviceAliasIds && widgetConfig.targetDeviceAliasIds.length) { widgetConfig.targetDevice = { @@ -346,9 +351,29 @@ export class DashboardUtilsService { } } } + + this.removeTimewindowConfigIfUnused(widgetConfig, type); return widgetConfig; } + public removeTimewindowConfigIfUnused(widgetConfig: WidgetConfig, type: widgetType) { + const widgetHasTimewindow = widgetTypeHasTimewindow(type) || (type === widgetType.latest && datasourcesHasAggregation(widgetConfig.datasources)); + if (!widgetHasTimewindow || widgetConfig.useDashboardTimewindow) { + delete widgetConfig.displayTimewindow; + delete widgetConfig.timewindow; + delete widgetConfig.timewindowStyle; + + if (!widgetHasTimewindow) { + delete widgetConfig.useDashboardTimewindow; + } + } + } + + public prepareWidgetForSaving(widget: Widget): Widget { + this.removeTimewindowConfigIfUnused(widget.config, widget.type); + return widget; + } + public prepareWidgetForScadaLayout(widget: Widget, isScada: boolean): Widget { const config = widget.config; config.showTitle = false; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 60d05d4c86..4c528fd55a 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -1322,6 +1322,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } private addWidgetToDashboard(widget: Widget) { + this.dashboardUtils.prepareWidgetForSaving(widget); if (this.addingLayoutCtx) { this.addWidgetToLayout(widget, this.addingLayoutCtx.id); this.addingLayoutCtx = null; @@ -1409,7 +1410,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC saveWidget() { this.editWidgetComponent.widgetFormGroup.markAsPristine(); - const widget = deepClone(this.editingWidget); + const widget = this.dashboardUtils.prepareWidgetForSaving(deepClone(this.editingWidget)); const widgetLayout = deepClone(this.editingWidgetLayout); const id = this.editingWidgetOriginal.id; this.dashboardConfiguration.widgets[id] = widget; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts index ec6af2857c..b359a16f51 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts @@ -23,11 +23,19 @@ import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { AbstractControl, UntypedFormGroup } from '@angular/forms'; -import { DataKey, DatasourceType, Widget, WidgetConfigMode, widgetType } from '@shared/models/widget.models'; +import { + DataKey, + DatasourceType, + Widget, + widgetTypeCanHaveTimewindow, + WidgetConfigMode, + widgetType +} from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; -import { isDefinedAndNotNull } from '@core/utils'; +import { isDefinedAndNotNull, isUndefinedOrNull } from '@core/utils'; import { IAliasController } from '@core/api/widget-api.models'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { initModelFromDefaultTimewindow } from '@shared/models/time/time.models'; export type WidgetConfigCallbacks = DatasourceCallbacks & WidgetActionCallbacks; @@ -107,6 +115,11 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement if (this.isAdd) { this.setupDefaults(widgetConfig); } + if (widgetTypeCanHaveTimewindow(widgetConfig.widgetType) && isUndefinedOrNull(widgetConfig.config.timewindow)) { + widgetConfig.config.timewindow = initModelFromDefaultTimewindow(null, + widgetConfig.widgetType === widgetType.latest, false, this.widgetConfigComponent.timeService, + widgetConfig.widgetType === widgetType.timeseries); + } this.onConfigSet(widgetConfig); this.updateValidators(false); for (const trigger of this.validatorTriggers()) { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 4c2d3d1f43..3cc9d4c6d1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -38,6 +38,7 @@ import { TargetDevice, targetDeviceValid, Widget, + widgetTypeCanHaveTimewindow, WidgetConfigMode, widgetType } from '@shared/models/widget.models'; @@ -53,7 +54,7 @@ import { Validators } from '@angular/forms'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; -import { deepClone, genNextLabel, isDefined, isObject } from '@app/core/utils'; +import { deepClone, genNextLabel, isDefined, isDefinedAndNotNull, isObject } from '@app/core/utils'; import { alarmFields, AlarmSearchStatus } from '@shared/models/alarm.models'; import { IAliasController } from '@core/api/widget-api.models'; import { EntityAlias } from '@shared/models/alias.models'; @@ -84,6 +85,8 @@ import { DataKeySettingsFunction } from '@home/components/widget/lib/settings/co import { defaultFormProperties, FormProperty } from '@shared/models/dynamic-form.models'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { WidgetService } from '@core/http/widget.service'; +import { TimeService } from '@core/services/time.service'; +import { initModelFromDefaultTimewindow } from '@shared/models/time/time.models'; import Timeout = NodeJS.Timeout; @Component({ @@ -201,6 +204,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe constructor(protected store: Store, private utils: UtilsService, private entityService: EntityService, + public timeService: TimeService, private dialog: MatDialog, public translate: TranslateService, private fb: UntypedFormBuilder, @@ -366,16 +370,16 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.dataSettings = this.fb.group({}); this.targetDeviceSettings = this.fb.group({}); this.advancedSettings = this.fb.group({}); - if (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.alarm || this.widgetType === widgetType.latest) { + if (widgetTypeCanHaveTimewindow(this.widgetType)) { this.dataSettings.addControl('timewindowConfig', this.fb.control({ - useDashboardTimewindow: true, - displayTimewindow: true, + useDashboardTimewindow: this.widgetType !== widgetType.latest, + displayTimewindow: this.widgetType !== widgetType.latest, timewindow: null, timewindowStyle: null })); - if (this.widgetType === widgetType.alarm) { - this.dataSettings.addControl('alarmFilterConfig', this.fb.control(null)); - } + } + if (this.widgetType === widgetType.alarm) { + this.dataSettings.addControl('alarmFilterConfig', this.fb.control(null)); } if (this.modelValue.isDataEnabled) { if (this.widgetType !== widgetType.rpc && @@ -529,14 +533,17 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe }, {emitEvent: false} ); - if (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.alarm || this.widgetType === widgetType.latest) { + if (widgetTypeCanHaveTimewindow(this.widgetType)) { const useDashboardTimewindow = isDefined(config.useDashboardTimewindow) ? - config.useDashboardTimewindow : true; + config.useDashboardTimewindow : this.widgetType !== widgetType.latest; this.dataSettings.get('timewindowConfig').patchValue({ useDashboardTimewindow, displayTimewindow: isDefined(config.displayTimewindow) ? - config.displayTimewindow : true, - timewindow: config.timewindow, + config.displayTimewindow : this.widgetType !== widgetType.latest, + timewindow: isDefinedAndNotNull(config.timewindow) + ? config.timewindow + : initModelFromDefaultTimewindow(null, this.widgetType === widgetType.latest, this.onlyHistoryTimewindow(), + this.timeService, this.widgetType === widgetType.timeseries), timewindowStyle: config.timewindowStyle }, {emitEvent: false}); } diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 00b62cfb72..45ae5986d9 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -489,6 +489,14 @@ export const targetDeviceValid = (targetDevice?: TargetDevice): boolean => ((targetDevice.type === TargetDeviceType.device && !!targetDevice.deviceId) || (targetDevice.type === TargetDeviceType.entity && !!targetDevice.entityAliasId)); +export const widgetTypeHasTimewindow = (type: widgetType): boolean => { + return type === widgetType.timeseries || type === widgetType.alarm; +} + +export const widgetTypeCanHaveTimewindow = (type: widgetType): boolean => { + return widgetTypeHasTimewindow(type) || type === widgetType.latest; +} + export const datasourcesHasAggregation = (datasources?: Array): boolean => { if (datasources) { const foundDatasource = datasources.find(datasource => {