Browse Source

UI: Implement time series comparison widget settings.

pull/10562/head
Igor Kulikov 2 years ago
parent
commit
82ab52889b
  1. 8
      ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
  2. 37
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.html
  3. 54
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.scss
  4. 131
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.ts
  5. 38
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.html
  6. 53
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.scss
  7. 110
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.ts
  8. 87
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.html
  9. 39
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts
  10. 6
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html
  11. 4
      ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts
  12. 2
      ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts
  13. 7
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
  14. 8
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
  15. 29
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.html
  16. 19
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.ts
  17. 40
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.html
  18. 20
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.ts
  19. 28
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.html
  20. 108
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts
  21. 16
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component.html
  22. 8
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component.scss
  23. 37
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component.ts
  24. 14
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts
  25. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.html
  26. 7
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.scss
  27. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.ts
  28. 13
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts
  29. 2
      ui-ngx/src/app/modules/home/models/widget-component.models.ts
  30. 10
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  31. 12
      ui-ngx/src/form.scss

8
ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts

@ -110,6 +110,10 @@ import {
import {
TimeSeriesChartBasicConfigComponent
} from '@home/components/widget/config/basic/chart/time-series-chart-basic-config.component';
import { ComparisonKeyRowComponent } from '@home/components/widget/config/basic/chart/comparison-key-row.component';
import {
ComparisonKeysTableComponent
} from '@home/components/widget/config/basic/chart/comparison-keys-table.component';
@NgModule({
declarations: [
@ -145,7 +149,9 @@ import {
PowerButtonBasicConfigComponent,
SliderBasicConfigComponent,
ToggleButtonBasicConfigComponent,
TimeSeriesChartBasicConfigComponent
TimeSeriesChartBasicConfigComponent,
ComparisonKeyRowComponent,
ComparisonKeysTableComponent
],
imports: [
CommonModule,

37
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.html

@ -0,0 +1,37 @@
<!--
Copyright © 2016-2024 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.
-->
<div [formGroup]="keyRowFormGroup" class="tb-form-table-row tb-comparison-key-row">
<mat-checkbox class="tb-show-field" formControlName="showValuesForComparison"></mat-checkbox>
<tb-data-key-input
[editable]="false"
[removable]="false"
[datasourceType]="datasourceType"
[formControl]="keyFormControl">
</tb-data-key-input>
<div class="tb-label-field">
<mat-form-field class="tb-inline-field" appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="comparisonValuesLabel" placeholder="{{ 'widgets.time-series-chart.comparison.comparison-values-label-auto' | translate }}">
</mat-form-field>
</div>
<div class="tb-color-field">
<tb-color-input asBoxInput
colorClearButton
formControlName="color">
</tb-color-input>
</div>
</div>

54
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.scss

@ -0,0 +1,54 @@
/**
* Copyright © 2016-2024 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 '../../../../../../../../scss/constants';
.tb-comparison-key-row {
.tb-show-field {
width: 40px;
min-width: 40px;
}
.tb-data-key-input {
flex: 1;
@media #{$mat-gt-xs} {
min-width: 100px;
flex: 1 1 40%;
}
}
.tb-label-field, .tb-color-field {
display: flex;
flex-direction: row;
place-content: center;
align-items: center;
.tb-inline-field {
flex: 1;
}
}
.tb-label-field {
flex: 1;
@media #{$mat-gt-xs} {
min-width: 150px;
flex: 1 1 60%;
}
}
.tb-color-field {
width: 40px;
min-width: 40px;
}
}

131
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-key-row.component.ts

@ -0,0 +1,131 @@
///
/// Copyright © 2016-2024 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 { ChangeDetectorRef, Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormControl,
UntypedFormGroup
} from '@angular/forms';
import {
DataKey,
DataKeyComparisonSettings,
DataKeySettingsWithComparison,
DatasourceType
} from '@shared/models/widget.models';
import { deepClone } from '@core/utils';
@Component({
selector: 'tb-comparison-key-row',
templateUrl: './comparison-key-row.component.html',
styleUrls: ['./comparison-key-row.component.scss', '../../data-keys.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ComparisonKeyRowComponent),
multi: true
}
],
encapsulation: ViewEncapsulation.None
})
export class ComparisonKeyRowComponent implements ControlValueAccessor, OnInit {
@Input()
disabled: boolean;
@Input()
datasourceType: DatasourceType;
keyFormControl: UntypedFormControl;
keyRowFormGroup: UntypedFormGroup;
modelValue: DataKey;
private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder,
private cd: ChangeDetectorRef) {
}
ngOnInit() {
this.keyFormControl = this.fb.control(null, []);
this.keyRowFormGroup = this.fb.group({
showValuesForComparison: [null, []],
comparisonValuesLabel: [null, []],
color: [null, []]
});
this.keyRowFormGroup.valueChanges.subscribe(
() => this.updateModel()
);
this.keyRowFormGroup.get('showValuesForComparison').valueChanges.subscribe(() => this.updateValidators());
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(_fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.keyFormControl.disable({emitEvent: false});
this.keyRowFormGroup.disable({emitEvent: false});
} else {
this.keyFormControl.enable({emitEvent: false});
this.keyRowFormGroup.enable({emitEvent: false});
this.updateValidators();
}
}
writeValue(value: DataKey): void {
this.modelValue = value;
const comparisonSettings = (value?.settings as DataKeySettingsWithComparison)?.comparisonSettings;
this.keyRowFormGroup.patchValue(
comparisonSettings, {emitEvent: false}
);
this.keyFormControl.patchValue(deepClone(this.modelValue), {emitEvent: false});
this.updateValidators();
this.cd.markForCheck();
}
private updateValidators() {
const showValuesForComparison: boolean = this.keyRowFormGroup.get('showValuesForComparison').value;
if (showValuesForComparison) {
this.keyFormControl.enable({emitEvent: false});
this.keyRowFormGroup.get('comparisonValuesLabel').enable({emitEvent: false});
this.keyRowFormGroup.get('color').enable({emitEvent: false});
} else {
this.keyFormControl.disable({emitEvent: false});
this.keyRowFormGroup.get('comparisonValuesLabel').disable({emitEvent: false});
this.keyRowFormGroup.get('color').disable({emitEvent: false});
}
}
private updateModel() {
const comparisonSettings: DataKeyComparisonSettings = this.keyRowFormGroup.value;
if (!this.modelValue.settings) {
this.modelValue.settings = {};
}
this.modelValue.settings.comparisonSettings = comparisonSettings;
this.propagateChange(this.modelValue);
}
}

38
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.html

@ -0,0 +1,38 @@
<!--
Copyright © 2016-2024 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.
-->
<div class="tb-comparison-keys-table tb-form-table">
<div class="tb-form-table-header">
<div class="tb-form-table-header-cell tb-show-header" translate>widgets.time-series-chart.comparison.show</div>
<div class="tb-form-table-header-cell tb-key-header" translate>datakey.key</div>
<div class="tb-form-table-header-cell tb-label-header" translate>datakey.label</div>
<div class="tb-form-table-header-cell tb-color-header" translate>datakey.color</div>
</div>
<div *ngIf="keysFormArray().controls.length; else noKeys" class="tb-form-table-body">
<div *ngFor="let keyControl of keysFormArray().controls; trackBy: trackByKey; let $index = index;">
<tb-comparison-key-row
fxFlex
[datasourceType]="datasourceType"
[formControl]="keyControl">
</tb-comparison-key-row>
</div>
</div>
</div>
<ng-template #noKeys>
<span fxLayoutAlign="center center"
class="tb-prompt">{{ 'widgets.chart.no-series' | translate }}</span>
</ng-template>

53
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.scss

@ -0,0 +1,53 @@
/**
* Copyright © 2016-2024 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 '../../../../../../../../scss/constants';
.tb-comparison-keys-table {
.tb-form-table-header-cell {
&.tb-show-header {
width: 40px;
min-width: 40px;
}
&.tb-key-header {
flex: 1;
@media #{$mat-gt-xs} {
min-width: 100px;
flex: 1 1 40%;
}
}
&.tb-label-header {
flex: 1;
@media #{$mat-gt-xs} {
min-width: 150px;
flex: 1 1 60%;
}
}
&.tb-color-header {
width: 40px;
min-width: 40px;
}
}
.tb-form-table-body {
tb-comparison-key-row {
overflow: hidden;
}
}
}

110
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/comparison-keys-table.component.ts

@ -0,0 +1,110 @@
///
/// Copyright © 2016-2024 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, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormArray,
UntypedFormBuilder,
UntypedFormGroup
} from '@angular/forms';
import { DataKey, DatasourceType } from '@shared/models/widget.models';
@Component({
selector: 'tb-comparison-keys-table',
templateUrl: './comparison-keys-table.component.html',
styleUrls: ['./comparison-keys-table.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ComparisonKeysTableComponent),
multi: true
}
],
encapsulation: ViewEncapsulation.None
})
export class ComparisonKeysTableComponent implements ControlValueAccessor, OnInit {
@Input()
disabled: boolean;
@Input()
datasourceType: DatasourceType;
keysListFormGroup: UntypedFormGroup;
get noKeys(): boolean {
const keys: DataKey[] = this.keysListFormGroup.get('keys').value;
return keys.length === 0;
}
private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder) {
}
ngOnInit() {
this.keysListFormGroup = this.fb.group({
keys: [this.fb.array([]), []]
});
this.keysListFormGroup.valueChanges.subscribe(
() => {
const keys: DataKey[] = this.keysListFormGroup.get('keys').value;
this.propagateChange(keys);
}
);
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(_fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
if (isDisabled) {
this.keysListFormGroup.disable({emitEvent: false});
} else {
this.keysListFormGroup.enable({emitEvent: false});
}
}
writeValue(value: DataKey[] | undefined): void {
this.keysListFormGroup.setControl('keys', this.prepareKeysFormArray(value), {emitEvent: false});
}
keysFormArray(): UntypedFormArray {
return this.keysListFormGroup.get('keys') as UntypedFormArray;
}
trackByKey(_index: number, keyControl: AbstractControl): any {
return keyControl;
}
private prepareKeysFormArray(keys: DataKey[] | undefined): UntypedFormArray {
const keysControls: Array<AbstractControl> = [];
if (keys) {
keys.forEach((key) => {
keysControls.push(this.fb.control(key, []));
});
}
return this.fb.array(keysControls);
}
}

87
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.html

@ -25,22 +25,77 @@
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
timeSeriesChart
[yAxisIds]="yAxisIds"
[showTimeSeriesType]="chartType === TimeSeriesChartType.default"
hideSourceSelection
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div fxLayout="row" fxLayoutAlign="space-between center">
<div class="tb-form-panel-title">{{ 'widgets.chart.series' | translate }}</div>
<tb-toggle-select [ngModel]="seriesMode" (ngModelChange)="seriesModeChange($event)"
[ngModelOptions]="{ standalone: true }">
<tb-toggle-option value="series">{{ 'widgets.chart.series' | translate }}</tb-toggle-option>
<tb-toggle-option value="comparison">{{ 'widgets.time-series-chart.comparison.comparison' | translate }}</tb-toggle-option>
</tb-toggle-select>
</div>
<tb-data-keys-panel
*ngIf="seriesMode === 'series'"
hidePanel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
timeSeriesChart
[yAxisIds]="yAxisIds"
[showTimeSeriesType]="chartType === TimeSeriesChartType.default"
hideSourceSelection
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div *ngIf="seriesMode === 'comparison'" class="tb-form-row no-border no-padding column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="comparisonEnabled">
{{ 'widgets.time-series-chart.comparison.comparison' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="timeForComparison">
<mat-option [value]="'previousInterval'">
{{ 'widgets.chart.time-for-comparison-previous-interval' | translate }}
</mat-option>
<mat-option [value]="'days'">
{{ 'widgets.chart.time-for-comparison-days' | translate }}
</mat-option>
<mat-option [value]="'weeks'">
{{ 'widgets.chart.time-for-comparison-weeks' | translate }}
</mat-option>
<mat-option [value]="'months'">
{{ 'widgets.chart.time-for-comparison-months' | translate }}
</mat-option>
<mat-option [value]="'years'">
{{ 'widgets.chart.time-for-comparison-years' | translate }}
</mat-option>
<mat-option [value]="'customInterval'">
{{ 'widgets.chart.time-for-comparison-custom-interval' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [fxShow]="timeSeriesChartWidgetConfigForm.get('timeForComparison').value === 'customInterval'"
appearance="outline" class="number flex-lt-md" subscriptSizing="dynamic">
<input matInput formControlName="comparisonCustomIntervalValue" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-time-series-chart-axis-settings-button
axisType="xAxis"
panelTitle="{{ 'widgets.time-series-chart.axis.comparison-x-axis-settings' | translate }}"
formControlName="comparisonXAxis">
</tb-time-series-chart-axis-settings-button>
</div>
</div>
<tb-comparison-keys-table
*ngIf="seriesMode === 'comparison'"
[datasourceType]="datasource?.type"
formControlName="series">
</tb-comparison-keys-table>
</div>
<tb-time-series-chart-states-panel
*ngIf="chartType === TimeSeriesChartType.state"
formControlName="states">

39
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/time-series-chart-basic-config.component.ts

@ -23,6 +23,7 @@ import { WidgetConfigComponentData } from '@home/models/widget-component.models'
import {
DataKey,
Datasource,
DatasourceType,
legendPositions,
legendPositionTranslationMap,
WidgetConfig,
@ -89,6 +90,8 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
chartType: TimeSeriesChartType = TimeSeriesChartType.default;
seriesMode = 'series';
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private $injector: Injector,
@ -105,6 +108,11 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
}
}
seriesModeChange(seriesMode: string) {
this.seriesMode = seriesMode;
this.updateSeriesState();
}
protected configForm(): UntypedFormGroup {
return this.timeSeriesChartWidgetConfigForm;
}
@ -135,6 +143,7 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
comparisonEnabled: [settings.comparisonEnabled, []],
timeForComparison: [settings.timeForComparison, []],
comparisonCustomIntervalValue: [settings.comparisonCustomIntervalValue, [Validators.min(0)]],
comparisonXAxis: [settings.comparisonXAxis, []],
thresholds: [settings.thresholds, []],
@ -187,6 +196,7 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
if (this.chartType === TimeSeriesChartType.state) {
this.timeSeriesChartWidgetConfigForm.addControl('states', this.fb.control(settings.states, []));
}
this.timeSeriesChartWidgetConfigForm.get('comparisonEnabled').valueChanges.subscribe(() => this.updateSeriesState());
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
@ -209,6 +219,7 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
this.widgetConfig.config.settings.comparisonEnabled = config.comparisonEnabled;
this.widgetConfig.config.settings.timeForComparison = config.timeForComparison;
this.widgetConfig.config.settings.comparisonCustomIntervalValue = config.comparisonCustomIntervalValue;
this.widgetConfig.config.settings.comparisonXAxis = config.comparisonXAxis;
this.widgetConfig.config.settings.thresholds = config.thresholds;
@ -254,16 +265,27 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showIcon', 'showLegend', 'showTooltip', 'tooltipShowDate'];
return ['comparisonEnabled', 'showTitle', 'showIcon', 'showLegend', 'showTooltip', 'tooltipShowDate'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const comparisonEnabled: boolean = this.timeSeriesChartWidgetConfigForm.get('comparisonEnabled').value;
const showTitle: boolean = this.timeSeriesChartWidgetConfigForm.get('showTitle').value;
const showIcon: boolean = this.timeSeriesChartWidgetConfigForm.get('showIcon').value;
const showLegend: boolean = this.timeSeriesChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.timeSeriesChartWidgetConfigForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.timeSeriesChartWidgetConfigForm.get('tooltipShowDate').value;
if (comparisonEnabled) {
this.timeSeriesChartWidgetConfigForm.get('timeForComparison').enable();
this.timeSeriesChartWidgetConfigForm.get('comparisonCustomIntervalValue').enable();
this.timeSeriesChartWidgetConfigForm.get('comparisonXAxis').enable();
} else {
this.timeSeriesChartWidgetConfigForm.get('timeForComparison').disable();
this.timeSeriesChartWidgetConfigForm.get('comparisonCustomIntervalValue').disable();
this.timeSeriesChartWidgetConfigForm.get('comparisonXAxis').disable();
}
if (showTitle) {
this.timeSeriesChartWidgetConfigForm.get('title').enable();
this.timeSeriesChartWidgetConfigForm.get('titleFont').enable();
@ -345,6 +367,19 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
}
}
private updateSeriesState() {
if (this.seriesMode === 'series') {
this.timeSeriesChartWidgetConfigForm.get('series').enable({emitEvent: false});
} else {
const comparisonEnabled = this.timeSeriesChartWidgetConfigForm.get('comparisonEnabled').value;
if (comparisonEnabled) {
this.timeSeriesChartWidgetConfigForm.get('series').enable({emitEvent: false});
} else {
this.timeSeriesChartWidgetConfigForm.get('series').disable({emitEvent: false});
}
}
}
private removeYaxisId(series: DataKey[], yAxisId: TimeSeriesChartYAxisId): boolean {
let changed = false;
if (series) {
@ -381,4 +416,6 @@ export class TimeSeriesChartBasicConfigComponent extends BasicWidgetConfigCompon
processor.update(Date.now());
return processor.formatted;
}
protected readonly DatasourceType = DatasourceType;
}

6
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html

@ -15,8 +15,10 @@
limitations under the License.
-->
<div class="tb-form-panel tb-data-keys-panel">
<div class="tb-form-panel-title">{{ panelTitle }}</div>
<div class="tb-form-panel tb-data-keys-panel"
[class.no-border]="hidePanel"
[class.no-padding]="hidePanel">
<div *ngIf="!hidePanel" class="tb-form-panel-title">{{ panelTitle }}</div>
<div class="tb-form-table">
<div class="tb-form-table-header no-padding-right">
<div *ngIf="hasAdditionalLatestDataKeys" class="tb-form-table-header-cell tb-source-header" translate>datakey.source</div>

4
ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts

@ -96,6 +96,10 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC
@Input()
deviceId: string;
@Input()
@coerceBoolean()
hidePanel = false;
@Input()
@coerceBoolean()
hideDataKeyColor = false;

2
ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts

@ -49,6 +49,7 @@ import { TbInject } from '@shared/decorators/tb-inject';
import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe';
import { UserSettingsService } from '@core/http/user-settings.service';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { UtilsService } from '@core/services/utils.service';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
@ -86,6 +87,7 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid
this.ctx.customDialog = $injector.get(CustomDialogService);
this.ctx.resourceService = $injector.get(ResourceService);
this.ctx.userSettingsService = $injector.get(UserSettingsService);
this.ctx.utilsService = $injector.get(UtilsService);
this.ctx.telemetryWsService = $injector.get(TelemetryWebsocketService);
this.ctx.date = $injector.get(DatePipe);
this.ctx.imagePipe = $injector.get(ImagePipe);

7
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts

@ -71,6 +71,7 @@ import { DatePipe } from '@angular/common';
import { BuiltinTextPosition } from 'zrender/src/core/types';
import { CartesianAxisOption } from 'echarts/types/src/coord/cartesian/AxisModel';
import { WidgetTimewindow } from '@shared/models/time/time.models';
import { UtilsService } from '@core/services/utils.service';
export enum TimeSeriesChartType {
default = 'default',
@ -932,6 +933,7 @@ export interface TimeSeriesChartXAxis extends TimeSeriesChartAxis {
export const createTimeSeriesYAxis = (units: string,
decimals: number,
settings: TimeSeriesChartYAxisSettings,
utils: UtilsService,
darkMode: boolean): TimeSeriesChartYAxis => {
const yAxisTickLabelStyle = createChartTextStyle(settings.tickLabelFont,
settings.tickLabelColor, darkMode, 'axis.tickLabel');
@ -986,7 +988,7 @@ export const createTimeSeriesYAxis = (units: string,
splitNumber,
interval,
ticksGenerator,
name: settings.label,
name: utils.customTranslation(settings.label, settings.label),
nameLocation: 'middle',
nameRotate: settings.position === AxisPosition.left ? 90 : -90,
nameTextStyle: {
@ -1044,6 +1046,7 @@ export const createTimeSeriesXAxis = (id: string,
settings: TimeSeriesChartXAxisSettings,
min: number, max: number,
datePipe: DatePipe,
utils: UtilsService,
darkMode: boolean): TimeSeriesChartXAxis => {
const xAxisTickLabelStyle = createChartTextStyle(settings.tickLabelFont,
settings.tickLabelColor, darkMode, 'axis.tickLabel');
@ -1060,7 +1063,7 @@ export const createTimeSeriesXAxis = (id: string,
scale: true,
position: settings.position,
id,
name: settings.label,
name: utils.customTranslation(settings.label, settings.label),
nameLocation: 'middle',
nameTextStyle: {
color: xAxisNameStyle.color,

8
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts

@ -170,7 +170,7 @@ export class TbTimeSeriesChart {
this.comparisonEnabled = !!this.ctx.defaultSubscription.comparisonEnabled;
this.stackMode = !this.comparisonEnabled && this.settings.stack;
if (this.settings.states && this.settings.states.length) {
this.stateValueConverter = new TimeSeriesChartStateValueConverter(this.ctx.dashboard.utils, this.settings.states);
this.stateValueConverter = new TimeSeriesChartStateValueConverter(this.ctx.utilsService, this.settings.states);
this.tooltipValueFormatFunction = this.stateValueConverter.tooltipFormatter;
}
const $dashboardPageElement = this.ctx.$containerParent.parents('.tb-dashboard-page');
@ -503,12 +503,12 @@ export class TbTimeSeriesChart {
private setupXAxes(): void {
const mainXAxis = createTimeSeriesXAxis('main', this.settings.xAxis, this.ctx.defaultSubscription.timeWindow.minTime,
this.ctx.defaultSubscription.timeWindow.maxTime, this.ctx.date, this.darkMode);
this.ctx.defaultSubscription.timeWindow.maxTime, this.ctx.date, this.ctx.utilsService, this.darkMode);
this.xAxisList.push(mainXAxis);
if (this.comparisonEnabled) {
const comparisonXAxis = createTimeSeriesXAxis('comparison', this.settings.comparisonXAxis,
this.ctx.defaultSubscription.comparisonTimeWindow.minTime, this.ctx.defaultSubscription.comparisonTimeWindow.maxTime,
this.ctx.date, this.darkMode);
this.ctx.date, this.ctx.utilsService, this.darkMode);
this.xAxisList.push(comparisonXAxis);
}
}
@ -526,7 +526,7 @@ export class TbTimeSeriesChart {
axisSettings.ticksGenerator = this.stateValueConverter.ticksGenerator;
axisSettings.ticksFormatter = this.stateValueConverter.ticksFormatter;
}
const yAxis = createTimeSeriesYAxis(units, decimals, axisSettings, this.darkMode);
const yAxis = createTimeSeriesYAxis(units, decimals, axisSettings, this.ctx.utilsService, this.darkMode);
this.yAxisList.push(yAxis);
}
}

29
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.html

@ -66,6 +66,35 @@
helpId="widget/lib/flot/tooltip_value_format_fn">
</tb-js-func>
</div>
<div *ngIf="comparisonEnabled" class="tb-form-panel tb-slide-toggle" formGroupName="comparisonSettings">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.comparison.settings</div>
<mat-expansion-panel class="tb-settings" [expanded]="timeSeriesChartKeySettingsForm.get('comparisonSettings.showValuesForComparison').value"
[disabled]="!timeSeriesChartKeySettingsForm.get('comparisonSettings.showValuesForComparison').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showValuesForComparison" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widgets.time-series-chart.comparison.show-values-for-comparison' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widgets.time-series-chart.comparison.comparison-values-label</div>
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="comparisonValuesLabel" placeholder="{{ 'widgets.time-series-chart.comparison.comparison-values-label-auto' | translate }}">
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.time-series-chart.comparison.comparison-data-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="color">
</tb-color-input>
</div>
</ng-template>
</mat-expansion-panel>
</div>
</ng-container>
<ng-template #chartTypeTitle>
<div class="tb-form-panel-title">{{ timeSeriesChartTypeTranslations.get(chartType) | translate }}</div>

19
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-key-settings.component.ts

@ -54,6 +54,8 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
yAxisIds: TimeSeriesChartYAxisId[];
comparisonEnabled: boolean;
functionScopeVariables = this.widgetService.getWidgetScopeVariables();
constructor(protected store: Store<AppState>,
@ -73,6 +75,7 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
}
const widgetSettings = (widgetConfig.config?.settings || {}) as TimeSeriesChartWidgetSettings;
this.yAxisIds = widgetSettings.yAxes ? Object.keys(widgetSettings.yAxes) : ['default'];
this.comparisonEnabled = !!widgetSettings.comparisonEnabled;
}
protected defaultSettings(): WidgetSettings {
@ -103,12 +106,14 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
}
protected validatorTriggers(): string[] {
return ['showInLegend', 'type'];
return ['showInLegend', 'type', 'comparisonSettings.showValuesForComparison'];
}
protected updateValidators(_emitEvent: boolean) {
const showInLegend: boolean = this.timeSeriesChartKeySettingsForm.get('showInLegend').value;
const type: TimeSeriesChartSeriesType = this.timeSeriesChartKeySettingsForm.get('type').value;
const showValuesForComparison: boolean =
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').get('showValuesForComparison').value;
if (showInLegend) {
this.timeSeriesChartKeySettingsForm.get('dataHiddenByDefault').enable();
} else {
@ -122,5 +127,17 @@ export class TimeSeriesChartKeySettingsComponent extends WidgetSettingsComponent
this.timeSeriesChartKeySettingsForm.get('lineSettings').disable();
this.timeSeriesChartKeySettingsForm.get('barSettings').enable();
}
if (this.comparisonEnabled) {
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').enable({emitEvent: false});
if (showValuesForComparison) {
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').get('comparisonValuesLabel').enable();
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').get('color').enable();
} else {
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').get('comparisonValuesLabel').disable();
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').get('color').disable();
}
} else {
this.timeSeriesChartKeySettingsForm.get('comparisonSettings').disable({emitEvent: false});
}
}
}

40
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.html

@ -16,6 +16,46 @@
-->
<ng-container [formGroup]="timeSeriesChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-row no-border no-padding column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="comparisonEnabled">
{{ 'widgets.time-series-chart.comparison.comparison' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="timeForComparison">
<mat-option [value]="'previousInterval'">
{{ 'widgets.chart.time-for-comparison-previous-interval' | translate }}
</mat-option>
<mat-option [value]="'days'">
{{ 'widgets.chart.time-for-comparison-days' | translate }}
</mat-option>
<mat-option [value]="'weeks'">
{{ 'widgets.chart.time-for-comparison-weeks' | translate }}
</mat-option>
<mat-option [value]="'months'">
{{ 'widgets.chart.time-for-comparison-months' | translate }}
</mat-option>
<mat-option [value]="'years'">
{{ 'widgets.chart.time-for-comparison-years' | translate }}
</mat-option>
<mat-option [value]="'customInterval'">
{{ 'widgets.chart.time-for-comparison-custom-interval' | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [fxShow]="timeSeriesChartWidgetSettingsForm.get('timeForComparison').value === 'customInterval'"
appearance="outline" class="number flex-lt-md" subscriptSizing="dynamic">
<input matInput formControlName="comparisonCustomIntervalValue" type="number" min="0" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-time-series-chart-axis-settings-button
axisType="xAxis"
panelTitle="{{ 'widgets.time-series-chart.axis.comparison-x-axis-settings' | translate }}"
formControlName="comparisonXAxis">
</tb-time-series-chart-axis-settings-button>
</div>
</div>
</div>
<tb-time-series-chart-states-panel
*ngIf="chartType === TimeSeriesChartType.state"
formControlName="states">

20
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-widget-settings.component.ts

@ -23,7 +23,7 @@ import {
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, isDefinedAndNotNull, mergeDeep } from '@core/utils';
@ -114,6 +114,11 @@ export class TimeSeriesChartWidgetSettingsComponent extends WidgetSettingsCompon
protected onSettingsSet(settings: WidgetSettings) {
this.timeSeriesChartWidgetSettingsForm = this.fb.group({
comparisonEnabled: [settings.comparisonEnabled, []],
timeForComparison: [settings.timeForComparison, []],
comparisonCustomIntervalValue: [settings.comparisonCustomIntervalValue, [Validators.min(0)]],
comparisonXAxis: [settings.comparisonXAxis, []],
yAxes: [settings.yAxes, []],
thresholds: [settings.thresholds, []],
@ -154,14 +159,25 @@ export class TimeSeriesChartWidgetSettingsComponent extends WidgetSettingsCompon
}
protected validatorTriggers(): string[] {
return ['showLegend', 'showTooltip', 'tooltipShowDate'];
return ['comparisonEnabled', 'showLegend', 'showTooltip', 'tooltipShowDate'];
}
protected updateValidators(emitEvent: boolean) {
const comparisonEnabled: boolean = this.timeSeriesChartWidgetSettingsForm.get('comparisonEnabled').value;
const showLegend: boolean = this.timeSeriesChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.timeSeriesChartWidgetSettingsForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.timeSeriesChartWidgetSettingsForm.get('tooltipShowDate').value;
if (comparisonEnabled) {
this.timeSeriesChartWidgetSettingsForm.get('timeForComparison').enable();
this.timeSeriesChartWidgetSettingsForm.get('comparisonCustomIntervalValue').enable();
this.timeSeriesChartWidgetSettingsForm.get('comparisonXAxis').enable();
} else {
this.timeSeriesChartWidgetSettingsForm.get('timeForComparison').disable();
this.timeSeriesChartWidgetSettingsForm.get('comparisonCustomIntervalValue').disable();
this.timeSeriesChartWidgetSettingsForm.get('comparisonXAxis').disable();
}
if (showLegend) {
this.timeSeriesChartWidgetSettingsForm.get('legendLabelFont').enable();
this.timeSeriesChartWidgetSettingsForm.get('legendLabelColor').enable();

28
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.html

@ -0,0 +1,28 @@
<!--
Copyright © 2016-2024 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.
-->
<button type="button"
mat-stroked-button
color="primary"
[disabled]="disabled"
#matButton
(click)="openAxisSettingsPopup($event, matButton)"
matTooltip="{{ panelTitle }}"
matTooltipPosition="above">
{{ (axisType === 'xAxis' ? 'widgets.time-series-chart.axis.x-axis' : 'widgets.time-series-chart.axis.y-axis') | translate }}
<tb-icon matButtonIcon>settings</tb-icon>
</button>

108
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component.ts

@ -0,0 +1,108 @@
///
/// Copyright © 2016-2024 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, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { coerceBoolean } from '@shared/decorators/coercion';
import { TimeSeriesChartAxisSettings } from '@home/components/widget/lib/chart/time-series-chart.models';
import {
TimeSeriesChartAxisSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component';
@Component({
selector: 'tb-time-series-chart-axis-settings-button',
templateUrl: './time-series-chart-axis-settings-button.component.html',
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TimeSeriesChartAxisSettingsButtonComponent),
multi: true
}
]
})
export class TimeSeriesChartAxisSettingsButtonComponent implements OnInit, ControlValueAccessor {
@Input()
disabled: boolean;
@Input()
axisType: 'xAxis' | 'yAxis' = 'xAxis';
@Input()
panelTitle: string;
@Input()
@coerceBoolean()
advanced = false;
private modelValue: TimeSeriesChartAxisSettings;
private propagateChange = null;
constructor(private popoverService: TbPopoverService,
private renderer: Renderer2,
private viewContainerRef: ViewContainerRef) {}
ngOnInit(): void {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(_fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
writeValue(value: TimeSeriesChartAxisSettings): void {
this.modelValue = value;
}
openAxisSettingsPopup($event: Event, matButton: MatButton) {
if ($event) {
$event.stopPropagation();
}
const trigger = matButton._elementRef.nativeElement;
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
const ctx: any = {
axisSettings: this.modelValue,
axisType: this.axisType,
panelTitle: this.panelTitle,
advanced: this.advanced
};
const axisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null,
ctx,
{},
{}, {}, true);
axisSettingsPanelPopover.tbComponentRef.instance.popover = axisSettingsPanelPopover;
axisSettingsPanelPopover.tbComponentRef.instance.axisSettingsApplied.subscribe((axisSettings) => {
axisSettingsPanelPopover.hide();
this.modelValue = axisSettings;
this.propagateChange(this.modelValue);
});
}
}
}

16
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-settings-panel.component.html → ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component.html

@ -15,17 +15,17 @@
limitations under the License.
-->
<div class="tb-y-axis-settings-panel" [formGroup]="yAxisSettingsFormGroup">
<div class="tb-y-axis-settings-title">{{ 'widgets.time-series-chart.axis.y-axis-settings' | translate }}</div>
<div class="tb-y-axis-settings-panel-content">
<div class="tb-axis-settings-panel" [formGroup]="axisSettingsFormGroup">
<div class="tb-axis-settings-title">{{ panelTitle }}</div>
<div class="tb-axis-settings-panel-content">
<tb-time-series-chart-axis-settings
formControlName="yAxis"
formControlName="axis"
alwaysExpanded
[advanced]="advanced"
axisType="yAxis">
[axisType]="axisType">
</tb-time-series-chart-axis-settings>
</div>
<div class="tb-y-axis-settings-panel-buttons">
<div class="tb-axis-settings-panel-buttons">
<button mat-button
color="primary"
type="button"
@ -35,8 +35,8 @@
<button mat-raised-button
color="primary"
type="button"
(click)="applyYAxisSettings()"
[disabled]="yAxisSettingsFormGroup.invalid || !yAxisSettingsFormGroup.dirty">
(click)="applyAxisSettings()"
[disabled]="axisSettingsFormGroup.invalid || !axisSettingsFormGroup.dirty">
{{ 'action.apply' | translate }}
</button>
</div>

8
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-settings-panel.component.scss → ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component.scss

@ -15,7 +15,7 @@
*/
@import '../../../../../../../../../scss/constants';
.tb-y-axis-settings-panel {
.tb-axis-settings-panel {
width: 530px;
display: flex;
flex-direction: column;
@ -23,7 +23,7 @@
@media #{$mat-lt-md} {
width: 90vw;
}
.tb-y-axis-settings-panel-content {
.tb-axis-settings-panel-content {
display: flex;
flex-direction: column;
gap: 16px;
@ -31,14 +31,14 @@
margin: -10px;
padding: 10px;
}
.tb-y-axis-settings-title {
.tb-axis-settings-title {
font-size: 16px;
font-weight: 500;
line-height: 24px;
letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.87);
}
.tb-y-axis-settings-panel-buttons {
.tb-axis-settings-panel-buttons {
height: 40px;
display: flex;
flex-direction: row;

37
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-settings-panel.component.ts → ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component.ts

@ -17,40 +17,49 @@
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { TbPopoverComponent } from '@shared/components/popover.component';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { TimeSeriesChartYAxisSettings } from '@home/components/widget/lib/chart/time-series-chart.models';
import {
TimeSeriesChartAxisSettings,
TimeSeriesChartYAxisSettings
} from '@home/components/widget/lib/chart/time-series-chart.models';
import { coerceBoolean } from '@shared/decorators/coercion';
@Component({
selector: 'tb-time-series-chart-y-axis-settings-panel',
templateUrl: './time-series-chart-y-axis-settings-panel.component.html',
selector: 'tb-time-series-chart-axis-settings-panel',
templateUrl: './time-series-chart-axis-settings-panel.component.html',
providers: [],
styleUrls: ['./time-series-chart-y-axis-settings-panel.component.scss'],
styleUrls: ['./time-series-chart-axis-settings-panel.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TimeSeriesChartYAxisSettingsPanelComponent implements OnInit {
export class TimeSeriesChartAxisSettingsPanelComponent implements OnInit {
@Input()
yAxisSettings: TimeSeriesChartYAxisSettings;
axisType: 'xAxis' | 'yAxis' = 'xAxis';
@Input()
panelTitle: string;
@Input()
axisSettings: TimeSeriesChartAxisSettings;
@Input()
@coerceBoolean()
advanced = false;
@Input()
popover: TbPopoverComponent<TimeSeriesChartYAxisSettingsPanelComponent>;
popover: TbPopoverComponent<TimeSeriesChartAxisSettingsPanelComponent>;
@Output()
yAxisSettingsApplied = new EventEmitter<TimeSeriesChartYAxisSettings>();
axisSettingsApplied = new EventEmitter<TimeSeriesChartAxisSettings>();
yAxisSettingsFormGroup: UntypedFormGroup;
axisSettingsFormGroup: UntypedFormGroup;
constructor(private fb: UntypedFormBuilder) {
}
ngOnInit(): void {
this.yAxisSettingsFormGroup = this.fb.group(
this.axisSettingsFormGroup = this.fb.group(
{
yAxis: [this.yAxisSettings, []]
axis: [this.axisSettings, []]
}
);
}
@ -59,8 +68,8 @@ export class TimeSeriesChartYAxisSettingsPanelComponent implements OnInit {
this.popover?.hide();
}
applyYAxisSettings() {
const yAxisSettings = this.yAxisSettingsFormGroup.get('yAxis').getRawValue();
this.yAxisSettingsApplied.emit(yAxisSettings);
applyAxisSettings() {
const axisSettings = this.axisSettingsFormGroup.get('axis').getRawValue();
this.axisSettingsApplied.emit(axisSettings);
}
}

14
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts

@ -36,9 +36,10 @@ import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { coerceBoolean } from '@shared/decorators/coercion';
import {
TimeSeriesChartYAxisSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-settings-panel.component';
TimeSeriesChartAxisSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component';
import { deepClone } from '@core/utils';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'tb-time-series-chart-y-axis-row',
@ -76,6 +77,7 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder,
private translate: TranslateService,
private popoverService: TbPopoverService,
private renderer: Renderer2,
private viewContainerRef: ViewContainerRef,
@ -143,16 +145,18 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
this.popoverService.hidePopover(trigger);
} else {
const ctx: any = {
yAxisSettings: deepClone(this.modelValue),
axisType: 'yAxis',
panelTitle: this.translate.instant('widgets.time-series-chart.axis.y-axis-settings'),
axisSettings: deepClone(this.modelValue),
advanced: this.advanced
};
const yAxisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, TimeSeriesChartYAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null,
this.viewContainerRef, TimeSeriesChartAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null,
ctx,
{},
{}, {}, true);
yAxisSettingsPanelPopover.tbComponentRef.instance.popover = yAxisSettingsPanelPopover;
yAxisSettingsPanelPopover.tbComponentRef.instance.yAxisSettingsApplied.subscribe((yAxisSettings) => {
yAxisSettingsPanelPopover.tbComponentRef.instance.axisSettingsApplied.subscribe((yAxisSettings) => {
yAxisSettingsPanelPopover.hide();
this.modelValue = {...this.modelValue, ...yAxisSettings};
this.axisFormGroup.patchValue(

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.html

@ -19,6 +19,7 @@
[class.tb-suffix-absolute]="!keysFormControl.value?.length">
<mat-chip-grid #chipList [formControl]="keysFormControl">
<mat-chip-row class="tb-datakey-chip" *ngIf="modelValue?.type"
[removable]="removable"
(removed)="removeKey()">
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="4px" class="tb-attribute-chip">
<div class="tb-chip-labels">
@ -49,7 +50,8 @@
(click)="editKey()" mat-icon-button class="tb-mat-24">
<mat-icon class="tb-mat-18">edit</mat-icon>
</button>
<button matChipRemove
<button *ngIf="removable"
matChipRemove
type="button"
mat-icon-button class="tb-mat-24">
<mat-icon class="tb-mat-18">close</mat-icon>

7
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.scss

@ -16,6 +16,13 @@
.tb-data-key-input {
.mat-mdc-form-field.tb-inline-field.tb-key-field {
width: 100%;
&.mat-form-field-appearance-fill {
.mdc-text-field--filled.mdc-text-field--disabled {
&:before {
opacity: 0;
}
}
}
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) {
padding-left: 8px;
padding-right: 0;

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/data-key-input.component.ts

@ -98,6 +98,10 @@ export class DataKeyInputComponent implements ControlValueAccessor, OnInit, OnCh
@coerceBoolean()
editable = true;
@Input()
@coerceBoolean()
removable = true;
@Input()
datasourceType: DatasourceType;

13
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts

@ -116,8 +116,8 @@ import {
TimeSeriesChartYAxisRowComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component';
import {
TimeSeriesChartYAxisSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-settings-panel.component';
TimeSeriesChartAxisSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-panel.component';
import {
TimeSeriesChartAnimationSettingsComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-animation-settings.component';
@ -139,6 +139,9 @@ import {
import {
TimeSeriesChartStatesPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-states-panel.component';
import {
TimeSeriesChartAxisSettingsButtonComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings-button.component';
@NgModule({
declarations: [
@ -184,7 +187,8 @@ import {
TimeSeriesNoAggregationBarWidthSettingsComponent,
TimeSeriesChartYAxesPanelComponent,
TimeSeriesChartYAxisRowComponent,
TimeSeriesChartYAxisSettingsPanelComponent,
TimeSeriesChartAxisSettingsPanelComponent,
TimeSeriesChartAxisSettingsButtonComponent,
TimeSeriesChartAnimationSettingsComponent,
TimeSeriesChartFillSettingsComponent,
TimeSeriesChartThresholdSettingsComponent,
@ -241,7 +245,8 @@ import {
TimeSeriesNoAggregationBarWidthSettingsComponent,
TimeSeriesChartYAxesPanelComponent,
TimeSeriesChartYAxisRowComponent,
TimeSeriesChartYAxisSettingsPanelComponent,
TimeSeriesChartAxisSettingsPanelComponent,
TimeSeriesChartAxisSettingsButtonComponent,
TimeSeriesChartAnimationSettingsComponent,
TimeSeriesChartFillSettingsComponent,
TimeSeriesChartThresholdSettingsComponent,

2
ui-ngx/src/app/modules/home/models/widget-component.models.ts

@ -103,6 +103,7 @@ import { UserId } from '@shared/models/id/user-id';
import { UserSettingsService } from '@core/http/user-settings.service';
import { DynamicComponentModule } from '@core/services/dynamic-component-factory.service';
import { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models';
import { UtilsService } from '@core/services/utils.service';
export interface IWidgetAction {
name: string;
@ -194,6 +195,7 @@ export class WidgetContext {
customDialog: CustomDialogService;
resourceService: ResourceService;
userSettingsService: UserSettingsService;
utilsService: UtilsService;
telemetryWsService: TelemetryWebsocketService;
telemetrySubscribers?: TelemetrySubscriber[];
date: DatePipe;

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

@ -6749,6 +6749,15 @@
"bar-width": "Bar width",
"bar-width-relative": "Percentage of time window",
"bar-width-absolute": "Absolute (ms)",
"comparison": {
"comparison": "Comparison",
"show": "Show",
"settings": "Comparison settings",
"show-values-for-comparison": "Show historical data for comparison",
"comparison-values-label": "Comparison key label",
"comparison-values-label-auto": "Auto",
"comparison-data-color": "Comparison data color"
},
"threshold": {
"thresholds": "Thresholds",
"source": "Source",
@ -6802,6 +6811,7 @@
"x-axis": "X axis",
"y-axis": "Y axis",
"y-axis-settings": "Y axis settings",
"comparison-x-axis-settings": "Comparison X axis settings",
"remove-y-axis": "Remove Y axis",
"id": "Id",
"label": "Label",

12
ui-ngx/src/form.scss

@ -216,6 +216,18 @@
flex: 1;
width: auto;
}
&.flex-xs {
@media #{$mat-xs} {
width: auto;
flex: 1;
}
}
&.flex-lt-md {
@media #{$mat-lt-md} {
width: auto;
flex: 1;
}
}
}
.fixed-title-width {
min-width: 200px;

Loading…
Cancel
Save