UI: Implement widgets config basic mode. Widgets config minor refactoring.
This commit is contained in:
		
							parent
							
								
									4ab93c8c52
								
							
						
					
					
						commit
						1fe00ac46a
					
				@ -1,42 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2023 The Thingsboard Authors
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<ng-container [formGroup]="simpleCardWidgetConfigForm" >
 | 
			
		||||
  <tb-datasources
 | 
			
		||||
    [configMode]="basicMode"
 | 
			
		||||
    formControlName="datasources">
 | 
			
		||||
  </tb-datasources>
 | 
			
		||||
  <div class="tb-widget-config-panel">
 | 
			
		||||
    <div class="tb-widget-config-panel-title" translate>widget-config.appearance</div>
 | 
			
		||||
    <div class="tb-widget-config-row space-between">
 | 
			
		||||
      <div translate>widgets.simple-card.label-position</div>
 | 
			
		||||
      <mat-form-field appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
        <mat-select formControlName="labelPosition">
 | 
			
		||||
          <mat-option [value]="'left'">
 | 
			
		||||
            {{ 'widgets.simple-card.label-position-left' | translate }}
 | 
			
		||||
          </mat-option>
 | 
			
		||||
          <mat-option [value]="'top'">
 | 
			
		||||
            {{ 'widgets.simple-card.label-position-top' | translate }}
 | 
			
		||||
          </mat-option>
 | 
			
		||||
        </mat-select>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <tb-widget-actions-panel
 | 
			
		||||
    formControlName="actions">
 | 
			
		||||
  </tb-widget-actions-panel>
 | 
			
		||||
</ng-container>
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2023 The Thingsboard Authors
 | 
			
		||||
///
 | 
			
		||||
/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
/// you may not use this file except in compliance with the License.
 | 
			
		||||
/// You may obtain a copy of the License at
 | 
			
		||||
///
 | 
			
		||||
///     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
///
 | 
			
		||||
/// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
/// See the License for the specific language governing permissions and
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { BasicWidgetConfigComponent } from '@home/components/widget/widget-config.component.models';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-simple-card-basic-config',
 | 
			
		||||
  templateUrl: './simple-card-basic-config.component.html',
 | 
			
		||||
  styleUrls: ['../basic-config.scss', '../../widget-config.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent {
 | 
			
		||||
 | 
			
		||||
  simpleCardWidgetConfigForm: UntypedFormGroup;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private fb: UntypedFormBuilder) {
 | 
			
		||||
    super(store);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected configForm(): UntypedFormGroup {
 | 
			
		||||
    return this.simpleCardWidgetConfigForm;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onConfigSet(configData: WidgetConfigComponentData) {
 | 
			
		||||
    this.simpleCardWidgetConfigForm = this.fb.group({
 | 
			
		||||
      datasources: [configData.config.datasources, []],
 | 
			
		||||
      labelPosition: [configData.config.settings?.labelPosition, []],
 | 
			
		||||
      actions: [configData.config.actions || {}, []]
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected prepareOutputConfig(config: any): WidgetConfigComponentData {
 | 
			
		||||
    this.widgetConfig.config.datasources = this.simpleCardWidgetConfigForm.value.datasources;
 | 
			
		||||
    this.widgetConfig.config.actions = this.simpleCardWidgetConfigForm.value.actions;
 | 
			
		||||
    this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
 | 
			
		||||
    this.widgetConfig.config.settings.labelPosition = this.simpleCardWidgetConfigForm.value.labelPosition;
 | 
			
		||||
    return this.widgetConfig;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -24,7 +24,7 @@ import {
 | 
			
		||||
} from '@home/components/widget/basic-config/cards/simple-card-basic-config.component';
 | 
			
		||||
import {
 | 
			
		||||
  WidgetActionsPanelComponent
 | 
			
		||||
} from '@home/components/widget/basic-config/action/widget-actions-panel.component';
 | 
			
		||||
} from '@home/components/widget/basic-config/common/widget-actions-panel.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -0,0 +1,86 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2023 The Thingsboard Authors
 | 
			
		||||
 | 
			
		||||
    Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
    you may not use this file except in compliance with the License.
 | 
			
		||||
    You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
        http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
    Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
    distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
    See the License for the specific language governing permissions and
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<ng-container [formGroup]="simpleCardWidgetConfigForm">
 | 
			
		||||
  <tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
 | 
			
		||||
    [onlyHistoryTimewindow]="onlyHistoryTimewindow()"
 | 
			
		||||
    formControlName="timewindowConfig">
 | 
			
		||||
  </tb-timewindow-config-panel>
 | 
			
		||||
  <tb-datasources
 | 
			
		||||
    [configMode]="basicMode"
 | 
			
		||||
    hideDataKeyLabel
 | 
			
		||||
    hideDataKeyColor
 | 
			
		||||
    hideDataKeyUnits
 | 
			
		||||
    hideDataKeyDecimals
 | 
			
		||||
    formControlName="datasources">
 | 
			
		||||
  </tb-datasources>
 | 
			
		||||
  <div class="tb-widget-config-panel">
 | 
			
		||||
    <div class="tb-widget-config-panel-title" translate>widget-config.appearance</div>
 | 
			
		||||
    <div class="tb-widget-config-row">
 | 
			
		||||
      <div translate>widgets.simple-card.label</div>
 | 
			
		||||
      <mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
        <input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}">
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-widget-config-row space-between">
 | 
			
		||||
      <div translate>widgets.simple-card.label-position</div>
 | 
			
		||||
      <mat-form-field appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
        <mat-select formControlName="labelPosition">
 | 
			
		||||
          <mat-option [value]="'left'">
 | 
			
		||||
            {{ 'widgets.simple-card.label-position-left' | translate }}
 | 
			
		||||
          </mat-option>
 | 
			
		||||
          <mat-option [value]="'top'">
 | 
			
		||||
            {{ 'widgets.simple-card.label-position-top' | translate }}
 | 
			
		||||
          </mat-option>
 | 
			
		||||
        </mat-select>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-widget-config-row space-between">
 | 
			
		||||
      <div translate>widget-config.units-short</div>
 | 
			
		||||
      <mat-form-field appearance="outline" class="center" subscriptSizing="dynamic">
 | 
			
		||||
        <input matInput formControlName="units" placeholder="{{ 'widget-config.set' | translate }}">
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-widget-config-row space-between">
 | 
			
		||||
      <div translate>widget-config.decimals-short</div>
 | 
			
		||||
      <mat-form-field appearance="outline" class="center number" subscriptSizing="dynamic">
 | 
			
		||||
        <input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-widget-config-row space-between same-padding">
 | 
			
		||||
      <div>{{ 'widget-config.text-color' | translate }}</div>
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
 | 
			
		||||
        <mat-divider vertical></mat-divider>
 | 
			
		||||
        <tb-color-input asBoxInput
 | 
			
		||||
                        formControlName="color">
 | 
			
		||||
        </tb-color-input>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-widget-config-row space-between same-padding">
 | 
			
		||||
      <div>{{ 'widget-config.background' | translate }}</div>
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
 | 
			
		||||
        <mat-divider vertical></mat-divider>
 | 
			
		||||
        <tb-color-input asBoxInput
 | 
			
		||||
                        formControlName="backgroundColor">
 | 
			
		||||
        </tb-color-input>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <tb-widget-actions-panel
 | 
			
		||||
    formControlName="actions">
 | 
			
		||||
  </tb-widget-actions-panel>
 | 
			
		||||
</ng-container>
 | 
			
		||||
@ -0,0 +1,110 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2023 The Thingsboard Authors
 | 
			
		||||
///
 | 
			
		||||
/// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
/// you may not use this file except in compliance with the License.
 | 
			
		||||
/// You may obtain a copy of the License at
 | 
			
		||||
///
 | 
			
		||||
///     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
///
 | 
			
		||||
/// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
/// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
/// See the License for the specific language governing permissions and
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { BasicWidgetConfigComponent } from '@home/components/widget/widget-config.component.models';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
import {
 | 
			
		||||
  Datasource,
 | 
			
		||||
  datasourcesHasAggregation,
 | 
			
		||||
  datasourcesHasOnlyComparisonAggregation
 | 
			
		||||
} from '@shared/models/widget.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-simple-card-basic-config',
 | 
			
		||||
  templateUrl: './simple-card-basic-config.component.html',
 | 
			
		||||
  styleUrls: ['../basic-config.scss', '../../widget-config.scss']
 | 
			
		||||
})
 | 
			
		||||
export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent {
 | 
			
		||||
 | 
			
		||||
  public get displayTimewindowConfig(): boolean {
 | 
			
		||||
    const datasources = this.simpleCardWidgetConfigForm.get('datasources').value;
 | 
			
		||||
    return datasourcesHasAggregation(datasources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public onlyHistoryTimewindow(): boolean {
 | 
			
		||||
    const datasources = this.simpleCardWidgetConfigForm.get('datasources').value;
 | 
			
		||||
    return datasourcesHasOnlyComparisonAggregation(datasources);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  simpleCardWidgetConfigForm: UntypedFormGroup;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private fb: UntypedFormBuilder) {
 | 
			
		||||
    super(store);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected configForm(): UntypedFormGroup {
 | 
			
		||||
    return this.simpleCardWidgetConfigForm;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onConfigSet(configData: WidgetConfigComponentData) {
 | 
			
		||||
    this.simpleCardWidgetConfigForm = this.fb.group({
 | 
			
		||||
      timewindowConfig: [{
 | 
			
		||||
        useDashboardTimewindow: configData.config.useDashboardTimewindow,
 | 
			
		||||
        displayTimewindow: configData.config.useDashboardTimewindow,
 | 
			
		||||
        timewindow: configData.config.timewindow
 | 
			
		||||
      }, []],
 | 
			
		||||
      datasources: [configData.config.datasources, []],
 | 
			
		||||
      label: [this.getDataKeyLabel(configData.config.datasources), []],
 | 
			
		||||
      labelPosition: [configData.config.settings?.labelPosition, []],
 | 
			
		||||
      units: [configData.config.units, []],
 | 
			
		||||
      decimals: [configData.config.decimals, []],
 | 
			
		||||
      color: [configData.config.color, []],
 | 
			
		||||
      backgroundColor: [configData.config.backgroundColor, []],
 | 
			
		||||
      actions: [configData.config.actions || {}, []]
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected prepareOutputConfig(config: any): WidgetConfigComponentData {
 | 
			
		||||
    this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow;
 | 
			
		||||
    this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow;
 | 
			
		||||
    this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow;
 | 
			
		||||
    this.widgetConfig.config.datasources = config.datasources;
 | 
			
		||||
    this.setDataKeyLabel(config.label, this.widgetConfig.config.datasources);
 | 
			
		||||
    this.widgetConfig.config.actions = config.actions;
 | 
			
		||||
    this.widgetConfig.config.units = config.units;
 | 
			
		||||
    this.widgetConfig.config.decimals = config.decimals;
 | 
			
		||||
    this.widgetConfig.config.color = config.color;
 | 
			
		||||
    this.widgetConfig.config.backgroundColor = config.backgroundColor;
 | 
			
		||||
    this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
 | 
			
		||||
    this.widgetConfig.config.settings.labelPosition = config.labelPosition;
 | 
			
		||||
    return this.widgetConfig;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getDataKeyLabel(datasources?: Datasource[]): string {
 | 
			
		||||
    if (datasources && datasources.length) {
 | 
			
		||||
      const dataKeys = datasources[0].dataKeys;
 | 
			
		||||
      if (dataKeys && dataKeys.length) {
 | 
			
		||||
        return dataKeys[0].label;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private setDataKeyLabel(label: string, datasources?: Datasource[]) {
 | 
			
		||||
    if (datasources && datasources.length) {
 | 
			
		||||
      const dataKeys = datasources[0].dataKeys;
 | 
			
		||||
      if (dataKeys && dataKeys.length) {
 | 
			
		||||
        dataKeys[0].label = label;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -40,6 +40,10 @@
 | 
			
		||||
      [widgetType]="data.widgetType"
 | 
			
		||||
      [showPostProcessing]="data.showPostProcessing"
 | 
			
		||||
      [callbacks]="data.callbacks"
 | 
			
		||||
      [hideDataKeyLabel]="data.hideDataKeyLabel"
 | 
			
		||||
      [hideDataKeyColor]="data.hideDataKeyColor"
 | 
			
		||||
      [hideDataKeyUnits]="data.hideDataKeyUnits"
 | 
			
		||||
      [hideDataKeyDecimals]="data.hideDataKeyDecimals"
 | 
			
		||||
      formControlName="dataKey">
 | 
			
		||||
    </tb-data-key-config>
 | 
			
		||||
  </div>
 | 
			
		||||
@ -40,6 +40,10 @@ export interface DataKeyConfigDialogData {
 | 
			
		||||
  entityAliasId?: string;
 | 
			
		||||
  showPostProcessing?: boolean;
 | 
			
		||||
  callbacks?: DataKeysCallbacks;
 | 
			
		||||
  hideDataKeyLabel: boolean;
 | 
			
		||||
  hideDataKeyColor: boolean;
 | 
			
		||||
  hideDataKeyUnits: boolean;
 | 
			
		||||
  hideDataKeyDecimals: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -40,11 +40,11 @@
 | 
			
		||||
        </mat-autocomplete>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
      <div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start center" fxLayoutAlign.xs fxLayoutGap="8px">
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
        <mat-form-field *ngIf="!hideDataKeyLabel" fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>datakey.label</mat-label>
 | 
			
		||||
          <input matInput formControlName="label" required>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <tb-color-input fxFlex
 | 
			
		||||
        <tb-color-input *ngIf="!hideDataKeyColor" fxFlex
 | 
			
		||||
          required
 | 
			
		||||
          label="{{'datakey.color' | translate}}"
 | 
			
		||||
          icon="format_color_fill"
 | 
			
		||||
@ -53,11 +53,11 @@
 | 
			
		||||
        </tb-color-input>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start center" fxLayoutAlign.xs fxLayoutGap="8px" *ngIf="modelValue.type !== dataKeyTypes.alarm">
 | 
			
		||||
        <mat-form-field fxFlex>
 | 
			
		||||
        <mat-form-field *ngIf="!hideDataKeyUnits" fxFlex>
 | 
			
		||||
          <mat-label translate>datakey.units</mat-label>
 | 
			
		||||
          <input matInput formControlName="units">
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <mat-form-field fxFlex>
 | 
			
		||||
        <mat-form-field *ngIf="!hideDataKeyDecimals" fxFlex>
 | 
			
		||||
          <mat-label translate>datakey.decimals</mat-label>
 | 
			
		||||
          <input matInput formControlName="decimals" type="number" min="0" max="15" step="1">
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
@ -52,6 +52,7 @@ import { Dashboard } from '@shared/models/dashboard.models';
 | 
			
		||||
import { IAliasController } from '@core/api/widget-api.models';
 | 
			
		||||
import { aggregationTranslations, AggregationType, ComparisonDuration } from '@shared/models/time/time.models';
 | 
			
		||||
import { genNextLabel } from '@core/utils';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-data-key-config',
 | 
			
		||||
@ -120,6 +121,22 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con
 | 
			
		||||
  @Input()
 | 
			
		||||
  showPostProcessing = true;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyLabel = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyColor = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyUnits = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyDecimals = false;
 | 
			
		||||
 | 
			
		||||
  @ViewChild('keyInput') keyInput: ElementRef;
 | 
			
		||||
 | 
			
		||||
  @ViewChild('funcBodyEdit') funcBodyEdit: JsFuncComponent;
 | 
			
		||||
@ -62,16 +62,16 @@
 | 
			
		||||
                          matTooltip="{{'datakey.timeseries' | translate }}"
 | 
			
		||||
                          matTooltipPosition="above">timeline</mat-icon>
 | 
			
		||||
              </ng-container>
 | 
			
		||||
              <span *ngIf="key.label !== key.name">{{key.label}}</span>
 | 
			
		||||
              <span *ngIf="!hideDataKeyLabel && key.label !== key.name">{{key.label}}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div *ngIf="key.label !== key.name" class="tb-chip-separator">: </div>
 | 
			
		||||
            <div *ngIf="!hideDataKeyLabel && key.label !== key.name" class="tb-chip-separator">: </div>
 | 
			
		||||
            <div class="tb-chip-label">
 | 
			
		||||
              <strong>
 | 
			
		||||
                <ng-container *ngTemplateOutlet="keyName; context:{key: key}"></ng-container>
 | 
			
		||||
              </strong>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div style="padding: 3px;">
 | 
			
		||||
          <div *ngIf="!hideDataKeyColor" style="padding: 3px;">
 | 
			
		||||
            <div class="tb-color-preview small box" (click)="showColorPicker(key)">
 | 
			
		||||
              <div class="tb-color-result" [ngStyle]="{background: key.color}"></div>
 | 
			
		||||
            </div>
 | 
			
		||||
@ -68,6 +68,7 @@ import { AggregationType } from '@shared/models/time/time.models';
 | 
			
		||||
import { DndDropEvent } from 'ngx-drag-drop/lib/dnd-dropzone.directive';
 | 
			
		||||
import { moveItemInArray } from '@angular/cdk/drag-drop';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
import { DatasourceComponent } from '@home/components/widget/datasource.component';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-data-keys',
 | 
			
		||||
@ -88,6 +89,22 @@ import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
})
 | 
			
		||||
export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChanges, ErrorStateMatcher {
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyLabel(): boolean {
 | 
			
		||||
    return this.datasourceComponent.hideDataKeyLabel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyColor(): boolean {
 | 
			
		||||
    return this.datasourceComponent.hideDataKeyColor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyUnits(): boolean {
 | 
			
		||||
    return this.datasourceComponent.hideDataKeyUnits;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyDecimals(): boolean {
 | 
			
		||||
    return this.datasourceComponent.hideDataKeyDecimals;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  datasourceTypes = DatasourceType;
 | 
			
		||||
  widgetTypes = widgetType;
 | 
			
		||||
  dataKeyTypes = DataKeyType;
 | 
			
		||||
@ -188,6 +205,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange
 | 
			
		||||
 | 
			
		||||
  constructor(private store: Store<AppState>,
 | 
			
		||||
              @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
 | 
			
		||||
              private datasourceComponent: DatasourceComponent,
 | 
			
		||||
              public translate: TranslateService,
 | 
			
		||||
              private utils: UtilsService,
 | 
			
		||||
              private dialogs: DialogService,
 | 
			
		||||
@ -480,7 +498,11 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange
 | 
			
		||||
          deviceId: this.deviceId,
 | 
			
		||||
          entityAliasId: this.entityAliasId,
 | 
			
		||||
          showPostProcessing: this.widgetType !== widgetType.alarm,
 | 
			
		||||
          callbacks: this.callbacks
 | 
			
		||||
          callbacks: this.callbacks,
 | 
			
		||||
          hideDataKeyLabel: this.hideDataKeyLabel,
 | 
			
		||||
          hideDataKeyColor: this.hideDataKeyColor,
 | 
			
		||||
          hideDataKeyUnits: this.hideDataKeyUnits,
 | 
			
		||||
          hideDataKeyDecimals: this.hideDataKeyDecimals
 | 
			
		||||
        }
 | 
			
		||||
      }).afterClosed().subscribe((updatedDataKey) => {
 | 
			
		||||
        if (updatedDataKey) {
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, forwardRef, Input, OnInit, Optional } from '@angular/core';
 | 
			
		||||
import {
 | 
			
		||||
  ControlValueAccessor,
 | 
			
		||||
  NG_VALIDATORS,
 | 
			
		||||
@ -41,6 +41,7 @@ import { EntityAliasSelectCallbacks } from '@home/components/alias/entity-alias-
 | 
			
		||||
import { FilterSelectCallbacks } from '@home/components/filter/filter-select.component.models';
 | 
			
		||||
import { DataKeysCallbacks } from '@home/components/widget/data-keys.component.models';
 | 
			
		||||
import { EntityType } from '@shared/models/entity-type.models';
 | 
			
		||||
import { DatasourcesComponent } from '@home/components/widget/datasources.component';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-datasource',
 | 
			
		||||
@ -122,6 +123,22 @@ export class DatasourceComponent implements ControlValueAccessor, OnInit, Valida
 | 
			
		||||
    return this.widgetConfigComponent.widget;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyLabel(): boolean {
 | 
			
		||||
    return this.datasourcesComponent?.hideDataKeyLabel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyColor(): boolean {
 | 
			
		||||
    return this.datasourcesComponent?.hideDataKeyColor;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyUnits(): boolean {
 | 
			
		||||
    return this.datasourcesComponent?.hideDataKeyUnits;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public get hideDataKeyDecimals(): boolean {
 | 
			
		||||
    return this.datasourcesComponent?.hideDataKeyDecimals;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
 | 
			
		||||
@ -138,6 +155,8 @@ export class DatasourceComponent implements ControlValueAccessor, OnInit, Valida
 | 
			
		||||
  private propagateChange = (_val: any) => {};
 | 
			
		||||
 | 
			
		||||
  constructor(private fb: UntypedFormBuilder,
 | 
			
		||||
              @Optional()
 | 
			
		||||
              private datasourcesComponent: DatasourcesComponent,
 | 
			
		||||
              private widgetConfigComponent: WidgetConfigComponent) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -41,6 +41,7 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { DataKeysCallbacks } from '@home/components/widget/data-keys.component.models';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-datasources',
 | 
			
		||||
@ -87,6 +88,22 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid
 | 
			
		||||
  @Input()
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyLabel = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyColor = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyUnits = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  hideDataKeyDecimals = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  configMode: WidgetConfigMode;
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { SharedModule } from '@app/shared/shared.module';
 | 
			
		||||
import { AlarmFilterConfigComponent } from '@home/components/alarm/alarm-filter-config.component';
 | 
			
		||||
import { AlarmAssigneeSelectComponent } from '@home/components/alarm/alarm-assignee-select.component';
 | 
			
		||||
import { DataKeysComponent } from '@home/components/widget/data-keys.component';
 | 
			
		||||
import { DataKeyConfigDialogComponent } from '@home/components/widget/data-key-config-dialog.component';
 | 
			
		||||
import { DataKeyConfigComponent } from '@home/components/widget/data-key-config.component';
 | 
			
		||||
@ -27,10 +28,12 @@ import { EntityAliasSelectComponent } from '@home/components/alias/entity-alias-
 | 
			
		||||
import { FilterSelectComponent } from '@home/components/filter/filter-select.component';
 | 
			
		||||
import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module';
 | 
			
		||||
import { WidgetSettingsComponent } from '@home/components/widget/widget-settings.component';
 | 
			
		||||
import { TimewindowConfigPanelComponent } from '@home/components/widget/timewindow-config-panel.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations:
 | 
			
		||||
    [
 | 
			
		||||
      AlarmAssigneeSelectComponent,
 | 
			
		||||
      AlarmFilterConfigComponent,
 | 
			
		||||
      DataKeysComponent,
 | 
			
		||||
      DataKeyConfigDialogComponent,
 | 
			
		||||
@ -39,6 +42,7 @@ import { WidgetSettingsComponent } from '@home/components/widget/widget-settings
 | 
			
		||||
      DatasourcesComponent,
 | 
			
		||||
      EntityAliasSelectComponent,
 | 
			
		||||
      FilterSelectComponent,
 | 
			
		||||
      TimewindowConfigPanelComponent,
 | 
			
		||||
      WidgetSettingsComponent
 | 
			
		||||
    ],
 | 
			
		||||
  imports: [
 | 
			
		||||
@ -47,6 +51,7 @@ import { WidgetSettingsComponent } from '@home/components/widget/widget-settings
 | 
			
		||||
    WidgetSettingsModule
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    AlarmAssigneeSelectComponent,
 | 
			
		||||
    AlarmFilterConfigComponent,
 | 
			
		||||
    DataKeysComponent,
 | 
			
		||||
    DataKeyConfigDialogComponent,
 | 
			
		||||
@ -55,6 +60,7 @@ import { WidgetSettingsComponent } from '@home/components/widget/widget-settings
 | 
			
		||||
    DatasourcesComponent,
 | 
			
		||||
    EntityAliasSelectComponent,
 | 
			
		||||
    FilterSelectComponent,
 | 
			
		||||
    TimewindowConfigPanelComponent,
 | 
			
		||||
    WidgetSettingsComponent
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
@ -80,6 +80,30 @@
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .mat-mdc-form-field {
 | 
			
		||||
    &.center {
 | 
			
		||||
      .mat-mdc-text-field-wrapper.mdc-text-field--outlined {
 | 
			
		||||
        .mat-mdc-form-field-infix {
 | 
			
		||||
          .mdc-text-field__input {
 | 
			
		||||
            text-align: center;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    &.number {
 | 
			
		||||
      .mat-mdc-text-field-wrapper.mdc-text-field--outlined {
 | 
			
		||||
        padding-right: 4px;
 | 
			
		||||
        .mat-mdc-form-field-infix {
 | 
			
		||||
          width: 80px;
 | 
			
		||||
          input.mdc-text-field__input[type=number]::-webkit-inner-spin-button,
 | 
			
		||||
          input.mdc-text-field__input[type=number]::-webkit-outer-spin-button {
 | 
			
		||||
            opacity: 1;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tb-widget-config-row {
 | 
			
		||||
    .mat-mdc-form-field {
 | 
			
		||||
      .mat-mdc-text-field-wrapper.mdc-text-field--outlined {
 | 
			
		||||
@ -97,27 +121,6 @@
 | 
			
		||||
          width: 72px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      &.center {
 | 
			
		||||
        .mat-mdc-text-field-wrapper.mdc-text-field--outlined {
 | 
			
		||||
          .mat-mdc-form-field-infix {
 | 
			
		||||
            .mdc-text-field__input {
 | 
			
		||||
              text-align: center;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      &.number {
 | 
			
		||||
        .mat-mdc-text-field-wrapper.mdc-text-field--outlined {
 | 
			
		||||
          padding-right: 4px;
 | 
			
		||||
          .mat-mdc-form-field-infix {
 | 
			
		||||
            width: 80px;
 | 
			
		||||
            input.mdc-text-field__input[type=number]::-webkit-inner-spin-button,
 | 
			
		||||
            input.mdc-text-field__input[type=number]::-webkit-outer-spin-button {
 | 
			
		||||
              opacity: 1;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -16,28 +16,27 @@
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  AfterViewInit,
 | 
			
		||||
  Component, ComponentFactoryResolver,
 | 
			
		||||
  Component,
 | 
			
		||||
  ComponentFactoryResolver,
 | 
			
		||||
  ComponentRef,
 | 
			
		||||
  forwardRef,
 | 
			
		||||
  Input, OnChanges,
 | 
			
		||||
  Input,
 | 
			
		||||
  OnChanges,
 | 
			
		||||
  OnDestroy,
 | 
			
		||||
  OnInit, SimpleChanges,
 | 
			
		||||
  OnInit,
 | 
			
		||||
  SimpleChanges,
 | 
			
		||||
  ViewChild,
 | 
			
		||||
  ViewContainerRef
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 | 
			
		||||
import {
 | 
			
		||||
  IRuleNodeConfigurationComponent,
 | 
			
		||||
  RuleNodeConfiguration,
 | 
			
		||||
  RuleNodeDefinition
 | 
			
		||||
} from '@shared/models/rule-node.models';
 | 
			
		||||
  ControlValueAccessor,
 | 
			
		||||
  NG_VALUE_ACCESSOR,
 | 
			
		||||
  UntypedFormBuilder,
 | 
			
		||||
  UntypedFormGroup,
 | 
			
		||||
  Validators
 | 
			
		||||
} from '@angular/forms';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { RuleChainService } from '@core/http/rule-chain.service';
 | 
			
		||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component';
 | 
			
		||||
import { deepClone } from '@core/utils';
 | 
			
		||||
import { RuleChainType } from '@shared/models/rule-chain.models';
 | 
			
		||||
import { JsonFormComponent } from '@shared/components/json-form/json-form.component';
 | 
			
		||||
import { JsonFormComponentData } from '@shared/components/json-form/json-form-component.models';
 | 
			
		||||
import { IWidgetSettingsComponent, Widget, WidgetSettings } from '@shared/models/widget.models';
 | 
			
		||||
@ -199,31 +199,12 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
  <ng-template #data>
 | 
			
		||||
    <div *ngIf="displayTimewindowConfig" [formGroup]="dataSettings" class="tb-widget-config-panel">
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="space-between center">
 | 
			
		||||
        <div class="tb-widget-config-panel-title" translate>timewindow.timewindow</div>
 | 
			
		||||
        <tb-toggle-header (valueChange)="dataSettings.get('useDashboardTimewindow').patchValue($event)" ignoreMdLgSize="true"
 | 
			
		||||
                          [options]="[
 | 
			
		||||
                                         { name: translate.instant('widget-config.use-dashboard-timewindow'), value: true},
 | 
			
		||||
                                         { name: translate.instant('widget-config.use-widget-timewindow'), value: false}
 | 
			
		||||
                                       ]"
 | 
			
		||||
                          [value]="dataSettings.get('useDashboardTimewindow').value" name="useDashboardTimewindow" useSelectOnMdLg="false">
 | 
			
		||||
        </tb-toggle-header>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="tb-widget-config-row">
 | 
			
		||||
        <tb-timewindow asButton="true"
 | 
			
		||||
                       strokedButton
 | 
			
		||||
                       isEdit="true"
 | 
			
		||||
                       alwaysDisplayTypePrefix
 | 
			
		||||
                       [historyOnly]="onlyHistoryTimewindow()"
 | 
			
		||||
                       quickIntervalOnly="{{ widgetType === widgetTypes.latest }}"
 | 
			
		||||
                       aggregation="{{ widgetType === widgetTypes.timeseries }}"
 | 
			
		||||
                       formControlName="timewindow"></tb-timewindow>
 | 
			
		||||
        <mat-slide-toggle class="mat-slide" formControlName="displayTimewindow">
 | 
			
		||||
          {{ 'widget-config.display-timewindow' | translate }}
 | 
			
		||||
        </mat-slide-toggle>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ng-container *ngIf="displayTimewindowConfig" [formGroup]="dataSettings">
 | 
			
		||||
      <tb-timewindow-config-panel
 | 
			
		||||
        [onlyHistoryTimewindow]="onlyHistoryTimewindow()"
 | 
			
		||||
        formControlName="timewindowConfig">
 | 
			
		||||
      </tb-timewindow-config-panel>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <div *ngIf="widgetType === widgetTypes.alarm" [formGroup]="dataSettings" class="tb-widget-config-panel" fxLayout="column" fxLayoutAlign="center">
 | 
			
		||||
      <tb-alarm-filter-config buttonMode="false" formControlName="alarmFilterConfig"></tb-alarm-filter-config>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,7 @@ import { Observable, of, Subscription } from 'rxjs';
 | 
			
		||||
import {
 | 
			
		||||
  IBasicWidgetConfigComponent,
 | 
			
		||||
  WidgetConfigCallbacks
 | 
			
		||||
} from '@home/components/widget/widget-config.component.models';
 | 
			
		||||
} from '@home/components/widget/config/widget-config.component.models';
 | 
			
		||||
import {
 | 
			
		||||
  EntityAliasDialogComponent,
 | 
			
		||||
  EntityAliasDialogData
 | 
			
		||||
@ -80,8 +80,9 @@ import { Filter, singleEntityFilterFromDeviceId } from '@shared/models/query/que
 | 
			
		||||
import { FilterDialogComponent, FilterDialogData } from '@home/components/filter/filter-dialog.component';
 | 
			
		||||
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
import { basicWidgetConfigComponentsMap } from '@home/components/widget/basic-config/basic-widget-config.module';
 | 
			
		||||
import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module';
 | 
			
		||||
import Timeout = NodeJS.Timeout;
 | 
			
		||||
import { TimewindowConfigData } from '@home/components/widget/timewindow-config-panel.component';
 | 
			
		||||
 | 
			
		||||
const emptySettingsSchema: JsonSchema = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
@ -188,6 +189,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
 | 
			
		||||
  private advancedSettingsSubscription: Subscription;
 | 
			
		||||
  private actionsSettingsSubscription: Subscription;
 | 
			
		||||
 | 
			
		||||
  private defaultConfigFormsType: widgetType;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private utils: UtilsService,
 | 
			
		||||
              private entityService: EntityService,
 | 
			
		||||
@ -356,12 +359,11 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
 | 
			
		||||
    this.targetDeviceSettings = this.fb.group({});
 | 
			
		||||
    this.advancedSettings = this.fb.group({});
 | 
			
		||||
    if (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.alarm || this.widgetType === widgetType.latest) {
 | 
			
		||||
      this.dataSettings.addControl('useDashboardTimewindow', this.fb.control(true));
 | 
			
		||||
      this.dataSettings.addControl('displayTimewindow', this.fb.control({value: true, disabled: true}));
 | 
			
		||||
      this.dataSettings.addControl('timewindow', this.fb.control({value: null, disabled: true}));
 | 
			
		||||
      this.dataSettings.get('useDashboardTimewindow').valueChanges.subscribe(() => {
 | 
			
		||||
        this.updateDataSettingsEnabledState();
 | 
			
		||||
      });
 | 
			
		||||
      this.dataSettings.addControl('timewindowConfig', this.fb.control({
 | 
			
		||||
        useDashboardTimewindow: true,
 | 
			
		||||
        displayTimewindow: true,
 | 
			
		||||
        timewindow: null
 | 
			
		||||
      }));
 | 
			
		||||
      if (this.widgetType === widgetType.alarm) {
 | 
			
		||||
        this.dataSettings.addControl('alarmFilterConfig', this.fb.control(null));
 | 
			
		||||
      }
 | 
			
		||||
@ -396,16 +398,19 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
 | 
			
		||||
 | 
			
		||||
  writeValue(value: WidgetConfigComponentData): void {
 | 
			
		||||
    this.modelValue = value;
 | 
			
		||||
    this.widgetType = this.modelValue?.widgetType;
 | 
			
		||||
    this.setupConfig();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private setupConfig() {
 | 
			
		||||
    this.destroyBasicModeComponent();
 | 
			
		||||
    this.removeChangeSubscriptions();
 | 
			
		||||
    if (this.hasBasicModeDirective && this.widgetConfigMode === WidgetConfigMode.basic) {
 | 
			
		||||
      this.setupBasicModeConfig();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setupDefaultConfig();
 | 
			
		||||
    if (this.modelValue) {
 | 
			
		||||
      this.destroyBasicModeComponent();
 | 
			
		||||
      this.removeChangeSubscriptions();
 | 
			
		||||
      if (this.hasBasicModeDirective && this.widgetConfigMode === WidgetConfigMode.basic) {
 | 
			
		||||
        this.setupBasicModeConfig();
 | 
			
		||||
      } else {
 | 
			
		||||
        this.setupDefaultConfig();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -451,123 +456,116 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private setupDefaultConfig() {
 | 
			
		||||
    if (this.modelValue) {
 | 
			
		||||
      if (this.widgetType !== this.modelValue.widgetType) {
 | 
			
		||||
        this.widgetType = this.modelValue.widgetType;
 | 
			
		||||
        this.buildForms();
 | 
			
		||||
    if (this.defaultConfigFormsType !== this.widgetType) {
 | 
			
		||||
      this.defaultConfigFormsType = this.widgetType;
 | 
			
		||||
      this.buildForms();
 | 
			
		||||
    }
 | 
			
		||||
    this.buildHeader();
 | 
			
		||||
    const config = this.modelValue.config;
 | 
			
		||||
    const layout = this.modelValue.layout;
 | 
			
		||||
    if (config) {
 | 
			
		||||
      const displayWidgetTitle = isDefined(config.showTitle) ? config.showTitle : false;
 | 
			
		||||
      this.widgetSettings.patchValue({
 | 
			
		||||
          title: config.title,
 | 
			
		||||
          showTitleIcon: isDefined(config.showTitleIcon) && displayWidgetTitle ? config.showTitleIcon : false,
 | 
			
		||||
          titleIcon: isDefined(config.titleIcon) ? config.titleIcon : '',
 | 
			
		||||
          iconColor: isDefined(config.iconColor) ? config.iconColor : 'rgba(0, 0, 0, 0.87)',
 | 
			
		||||
          iconSize: isDefined(config.iconSize) ? config.iconSize : '24px',
 | 
			
		||||
          titleTooltip: isDefined(config.titleTooltip) ? config.titleTooltip : '',
 | 
			
		||||
          showTitle: displayWidgetTitle,
 | 
			
		||||
          dropShadow: isDefined(config.dropShadow) ? config.dropShadow : true,
 | 
			
		||||
          enableFullscreen: isDefined(config.enableFullscreen) ? config.enableFullscreen : true,
 | 
			
		||||
          backgroundColor: config.backgroundColor,
 | 
			
		||||
          color: config.color,
 | 
			
		||||
          padding: config.padding,
 | 
			
		||||
          margin: config.margin,
 | 
			
		||||
          widgetStyle: isDefined(config.widgetStyle) ? config.widgetStyle : {},
 | 
			
		||||
          widgetCss: isDefined(config.widgetCss) ? config.widgetCss : '',
 | 
			
		||||
          titleStyle: isDefined(config.titleStyle) ? config.titleStyle : {
 | 
			
		||||
            fontSize: '16px',
 | 
			
		||||
            fontWeight: 400
 | 
			
		||||
          },
 | 
			
		||||
          pageSize: isDefined(config.pageSize) ? config.pageSize : 1024,
 | 
			
		||||
          units: config.units,
 | 
			
		||||
          decimals: config.decimals,
 | 
			
		||||
          noDataDisplayMessage: isDefined(config.noDataDisplayMessage) ? config.noDataDisplayMessage : ''
 | 
			
		||||
        },
 | 
			
		||||
        {emitEvent: false}
 | 
			
		||||
      );
 | 
			
		||||
      this.updateWidgetSettingsEnabledState();
 | 
			
		||||
      this.actionsSettings.patchValue(
 | 
			
		||||
        {
 | 
			
		||||
          actions: config.actions || {}
 | 
			
		||||
        },
 | 
			
		||||
        {emitEvent: false}
 | 
			
		||||
      );
 | 
			
		||||
      if (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.alarm || this.widgetType === widgetType.latest) {
 | 
			
		||||
        const useDashboardTimewindow = isDefined(config.useDashboardTimewindow) ?
 | 
			
		||||
          config.useDashboardTimewindow : true;
 | 
			
		||||
        this.dataSettings.get('timewindowConfig').patchValue({
 | 
			
		||||
          useDashboardTimewindow,
 | 
			
		||||
          displayTimewindow: isDefined(config.displayTimewindow) ?
 | 
			
		||||
            config.displayTimewindow : true,
 | 
			
		||||
          timewindow: config.timewindow
 | 
			
		||||
        }, {emitEvent: false});
 | 
			
		||||
      }
 | 
			
		||||
      this.buildHeader();
 | 
			
		||||
      const config = this.modelValue.config;
 | 
			
		||||
      const layout = this.modelValue.layout;
 | 
			
		||||
      if (config) {
 | 
			
		||||
        const displayWidgetTitle = isDefined(config.showTitle) ? config.showTitle : false;
 | 
			
		||||
        this.widgetSettings.patchValue({
 | 
			
		||||
            title: config.title,
 | 
			
		||||
            showTitleIcon: isDefined(config.showTitleIcon) && displayWidgetTitle ? config.showTitleIcon : false,
 | 
			
		||||
            titleIcon: isDefined(config.titleIcon) ? config.titleIcon : '',
 | 
			
		||||
            iconColor: isDefined(config.iconColor) ? config.iconColor : 'rgba(0, 0, 0, 0.87)',
 | 
			
		||||
            iconSize: isDefined(config.iconSize) ? config.iconSize : '24px',
 | 
			
		||||
            titleTooltip: isDefined(config.titleTooltip) ? config.titleTooltip : '',
 | 
			
		||||
            showTitle: displayWidgetTitle,
 | 
			
		||||
            dropShadow: isDefined(config.dropShadow) ? config.dropShadow : true,
 | 
			
		||||
            enableFullscreen: isDefined(config.enableFullscreen) ? config.enableFullscreen : true,
 | 
			
		||||
            backgroundColor: config.backgroundColor,
 | 
			
		||||
            color: config.color,
 | 
			
		||||
            padding: config.padding,
 | 
			
		||||
            margin: config.margin,
 | 
			
		||||
            widgetStyle: isDefined(config.widgetStyle) ? config.widgetStyle : {},
 | 
			
		||||
            widgetCss: isDefined(config.widgetCss) ? config.widgetCss : '',
 | 
			
		||||
            titleStyle: isDefined(config.titleStyle) ? config.titleStyle : {
 | 
			
		||||
              fontSize: '16px',
 | 
			
		||||
              fontWeight: 400
 | 
			
		||||
            },
 | 
			
		||||
            pageSize: isDefined(config.pageSize) ? config.pageSize : 1024,
 | 
			
		||||
            units: config.units,
 | 
			
		||||
            decimals: config.decimals,
 | 
			
		||||
            noDataDisplayMessage: isDefined(config.noDataDisplayMessage) ? config.noDataDisplayMessage : ''
 | 
			
		||||
          },
 | 
			
		||||
          {emitEvent: false}
 | 
			
		||||
        );
 | 
			
		||||
        this.updateWidgetSettingsEnabledState();
 | 
			
		||||
        this.actionsSettings.patchValue(
 | 
			
		||||
          {
 | 
			
		||||
            actions: config.actions || {}
 | 
			
		||||
          },
 | 
			
		||||
          {emitEvent: false}
 | 
			
		||||
        );
 | 
			
		||||
        if (this.widgetType === widgetType.timeseries || this.widgetType === widgetType.alarm || this.widgetType === widgetType.latest) {
 | 
			
		||||
          const useDashboardTimewindow = isDefined(config.useDashboardTimewindow) ?
 | 
			
		||||
            config.useDashboardTimewindow : true;
 | 
			
		||||
          this.dataSettings.patchValue(
 | 
			
		||||
            { useDashboardTimewindow }, {emitEvent: false}
 | 
			
		||||
          );
 | 
			
		||||
          this.dataSettings.patchValue(
 | 
			
		||||
            { displayTimewindow: isDefined(config.displayTimewindow) ?
 | 
			
		||||
                config.displayTimewindow : true }, {emitEvent: false}
 | 
			
		||||
          );
 | 
			
		||||
          this.dataSettings.patchValue(
 | 
			
		||||
            { timewindow: config.timewindow }, {emitEvent: false}
 | 
			
		||||
          );
 | 
			
		||||
          this.updateDataSettingsEnabledState();
 | 
			
		||||
        }
 | 
			
		||||
        if (this.modelValue.isDataEnabled) {
 | 
			
		||||
          if (this.widgetType !== widgetType.rpc &&
 | 
			
		||||
            this.widgetType !== widgetType.alarm &&
 | 
			
		||||
            this.widgetType !== widgetType.static) {
 | 
			
		||||
            this.dataSettings.patchValue({ datasources: config.datasources},
 | 
			
		||||
              {emitEvent: false});
 | 
			
		||||
          } else if (this.widgetType === widgetType.rpc) {
 | 
			
		||||
            let targetDeviceAliasId: string;
 | 
			
		||||
            if (config.targetDeviceAliasIds && config.targetDeviceAliasIds.length > 0) {
 | 
			
		||||
              const aliasId = config.targetDeviceAliasIds[0];
 | 
			
		||||
              const entityAliases = this.aliasController.getEntityAliases();
 | 
			
		||||
              if (entityAliases[aliasId]) {
 | 
			
		||||
                targetDeviceAliasId = entityAliases[aliasId].id;
 | 
			
		||||
              } else {
 | 
			
		||||
                targetDeviceAliasId = null;
 | 
			
		||||
              }
 | 
			
		||||
      if (this.modelValue.isDataEnabled) {
 | 
			
		||||
        if (this.widgetType !== widgetType.rpc &&
 | 
			
		||||
          this.widgetType !== widgetType.alarm &&
 | 
			
		||||
          this.widgetType !== widgetType.static) {
 | 
			
		||||
          this.dataSettings.patchValue({ datasources: config.datasources},
 | 
			
		||||
            {emitEvent: false});
 | 
			
		||||
        } else if (this.widgetType === widgetType.rpc) {
 | 
			
		||||
          let targetDeviceAliasId: string;
 | 
			
		||||
          if (config.targetDeviceAliasIds && config.targetDeviceAliasIds.length > 0) {
 | 
			
		||||
            const aliasId = config.targetDeviceAliasIds[0];
 | 
			
		||||
            const entityAliases = this.aliasController.getEntityAliases();
 | 
			
		||||
            if (entityAliases[aliasId]) {
 | 
			
		||||
              targetDeviceAliasId = entityAliases[aliasId].id;
 | 
			
		||||
            } else {
 | 
			
		||||
              targetDeviceAliasId = null;
 | 
			
		||||
            }
 | 
			
		||||
            this.targetDeviceSettings.patchValue({
 | 
			
		||||
              targetDeviceAliasId
 | 
			
		||||
            }, {emitEvent: false});
 | 
			
		||||
          } else if (this.widgetType === widgetType.alarm) {
 | 
			
		||||
            this.dataSettings.patchValue(
 | 
			
		||||
              { alarmFilterConfig: isDefined(config.alarmFilterConfig) ?
 | 
			
		||||
                  config.alarmFilterConfig :
 | 
			
		||||
                  { statusList: [AlarmSearchStatus.ACTIVE], searchPropagatedAlarms: true },
 | 
			
		||||
                alarmSource: config.alarmSource }, {emitEvent: false}
 | 
			
		||||
            );
 | 
			
		||||
          } else {
 | 
			
		||||
            targetDeviceAliasId = null;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.updateSchemaForm(config.settings);
 | 
			
		||||
 | 
			
		||||
        if (layout) {
 | 
			
		||||
          this.layoutSettings.patchValue(
 | 
			
		||||
            {
 | 
			
		||||
              mobileOrder: layout.mobileOrder,
 | 
			
		||||
              mobileHeight: layout.mobileHeight,
 | 
			
		||||
              mobileHide: layout.mobileHide,
 | 
			
		||||
              desktopHide: layout.desktopHide
 | 
			
		||||
            },
 | 
			
		||||
            {emitEvent: false}
 | 
			
		||||
          );
 | 
			
		||||
        } else {
 | 
			
		||||
          this.layoutSettings.patchValue(
 | 
			
		||||
            {
 | 
			
		||||
              mobileOrder: null,
 | 
			
		||||
              mobileHeight: null,
 | 
			
		||||
              mobileHide: false,
 | 
			
		||||
              desktopHide: false
 | 
			
		||||
            },
 | 
			
		||||
            {emitEvent: false}
 | 
			
		||||
          this.targetDeviceSettings.patchValue({
 | 
			
		||||
            targetDeviceAliasId
 | 
			
		||||
          }, {emitEvent: false});
 | 
			
		||||
        } else if (this.widgetType === widgetType.alarm) {
 | 
			
		||||
          this.dataSettings.patchValue(
 | 
			
		||||
            { alarmFilterConfig: isDefined(config.alarmFilterConfig) ?
 | 
			
		||||
                config.alarmFilterConfig :
 | 
			
		||||
                { statusList: [AlarmSearchStatus.ACTIVE], searchPropagatedAlarms: true },
 | 
			
		||||
              alarmSource: config.alarmSource }, {emitEvent: false}
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this.createChangeSubscriptions();
 | 
			
		||||
 | 
			
		||||
      this.updateSchemaForm(config.settings);
 | 
			
		||||
 | 
			
		||||
      if (layout) {
 | 
			
		||||
        this.layoutSettings.patchValue(
 | 
			
		||||
          {
 | 
			
		||||
            mobileOrder: layout.mobileOrder,
 | 
			
		||||
            mobileHeight: layout.mobileHeight,
 | 
			
		||||
            mobileHide: layout.mobileHide,
 | 
			
		||||
            desktopHide: layout.desktopHide
 | 
			
		||||
          },
 | 
			
		||||
          {emitEvent: false}
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        this.layoutSettings.patchValue(
 | 
			
		||||
          {
 | 
			
		||||
            mobileOrder: null,
 | 
			
		||||
            mobileHeight: null,
 | 
			
		||||
            mobileHide: false,
 | 
			
		||||
            desktopHide: false
 | 
			
		||||
          },
 | 
			
		||||
          {emitEvent: false}
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.createChangeSubscriptions();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateWidgetSettingsEnabledState() {
 | 
			
		||||
@ -595,17 +593,6 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateDataSettingsEnabledState() {
 | 
			
		||||
    const useDashboardTimewindow: boolean = this.dataSettings.get('useDashboardTimewindow').value;
 | 
			
		||||
    if (useDashboardTimewindow) {
 | 
			
		||||
      this.dataSettings.get('displayTimewindow').disable({emitEvent: false});
 | 
			
		||||
      this.dataSettings.get('timewindow').disable({emitEvent: false});
 | 
			
		||||
    } else {
 | 
			
		||||
      this.dataSettings.get('displayTimewindow').enable({emitEvent: false});
 | 
			
		||||
      this.dataSettings.get('timewindow').enable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateSchemaForm(settings?: any) {
 | 
			
		||||
    const widgetSettingsFormData: JsonFormComponentData = {};
 | 
			
		||||
    if (this.modelValue.settingsSchema && this.modelValue.settingsSchema.schema) {
 | 
			
		||||
@ -626,7 +613,13 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
 | 
			
		||||
  private updateDataSettings() {
 | 
			
		||||
    if (this.modelValue) {
 | 
			
		||||
      if (this.modelValue.config) {
 | 
			
		||||
        Object.assign(this.modelValue.config, this.dataSettings.value);
 | 
			
		||||
        let data = this.dataSettings.value;
 | 
			
		||||
        if (data.timewindowConfig) {
 | 
			
		||||
          const timewindowConfig: TimewindowConfigData = data.timewindowConfig;
 | 
			
		||||
          data = {...data, ...timewindowConfig};
 | 
			
		||||
          delete data.timewindowConfig;
 | 
			
		||||
        }
 | 
			
		||||
        Object.assign(this.modelValue.config, data);
 | 
			
		||||
      }
 | 
			
		||||
      this.propagateChange(this.modelValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user