Browse Source

clean up and propagation of limits values

pull/14488/head
Maksym Tsymbarov 10 months ago
parent
commit
ce3b257942
  1. 27
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
  2. 15
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/axis-scale-row.component.scss
  3. 67
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/axis-scale-row.component.ts
  4. 16
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts
  5. 31
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component.ts
  6. 10
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.html
  7. 24
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-row.component.ts

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

@ -594,10 +594,10 @@ export class TbTimeSeriesChart {
}
const yAxis = createTimeSeriesYAxis(unitSymbol, decimals, axisSettings, this.ctx.utilsService, this.darkMode, unitConvertor);
if (isDefinedAndNotNull(axisSettings.min)) {
this.processYAxisLimit(axisSettings.min, 'min', yAxis, axisLimitDatasources, unitConvertor);
this.processYAxisLimit(axisSettings.min as ValueSourceConfig, 'min', yAxis, axisLimitDatasources, unitConvertor);
}
if (isDefinedAndNotNull(axisSettings.max)) {
this.processYAxisLimit(axisSettings.max, 'max', yAxis, axisLimitDatasources, unitConvertor);
this.processYAxisLimit(axisSettings.max as ValueSourceConfig, 'max', yAxis, axisLimitDatasources, unitConvertor);
}
this.yAxisList.push(yAxis);
}
@ -605,22 +605,21 @@ export class TbTimeSeriesChart {
}
private processYAxisLimit(
limit: any,
limit: ValueSourceConfig,
limitType: 'min' | 'max',
yAxis: TimeSeriesChartYAxis,
axisLimitDatasources: Datasource[],
unitConvertor?: (value: number) => number
): void {
if (limit && typeof limit === 'object' && 'type' in limit) {
const axisLimit = limit as ValueSourceConfig;
if (axisLimit.type === ValueSourceType.latestKey) {
if (limit.type === ValueSourceType.latestKey) {
let latestDataKey: DataKey = null;
if (this.ctx.datasources.length) {
for (const datasource of this.ctx.datasources) {
latestDataKey = datasource.latestDataKeys?.find(d =>
(d.type === DataKeyType.function && d.label === axisLimit.latestKey) ||
(d.type !== DataKeyType.function && d.name === axisLimit.latestKey &&
d.type === axisLimit.latestKeyType));
(d.type === DataKeyType.function && d.label === limit.latestKey) ||
(d.type !== DataKeyType.function && d.name === limit.latestKey &&
d.type === limit.latestKeyType));
if (latestDataKey) {
break;
}
@ -633,8 +632,8 @@ export class TbTimeSeriesChart {
yAxis.maxLatestDataKey = latestDataKey;
}
}
} else if (axisLimit.type === ValueSourceType.entity) {
const entityAliasId = this.ctx.aliasController.getEntityAliasId(axisLimit.entityAlias);
} else if (limit.type === ValueSourceType.entity) {
const entityAliasId = this.ctx.aliasController.getEntityAliasId(limit.entityAlias);
if (entityAliasId) {
let datasource = axisLimitDatasources.find(d => d.entityAliasId === entityAliasId);
const entityDataKey: DataKey = {
@ -651,16 +650,16 @@ export class TbTimeSeriesChart {
} else {
datasource = {
type: DatasourceType.entity,
name: axisLimit.entityAlias,
aliasName: axisLimit.entityAlias,
name: limit.entityAlias,
aliasName: limit.entityAlias,
entityAliasId,
dataKeys: [entityDataKey]
};
axisLimitDatasources.push(datasource);
}
}
} else if (axisLimit.type === ValueSourceType.constant) {
const value = unitConvertor ? unitConvertor(axisLimit.value) : axisLimit.value;
} else if (limit.type === ValueSourceType.constant) {
const value = unitConvertor ? unitConvertor(limit.value) : limit.value;
if (limitType === 'min') {
yAxis.option.min = value;
} else {

15
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/axis-scale-row.component.scss

@ -1,15 +0,0 @@
/**
* Copyright © 2016-2025 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.
*/

67
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/axis-scale-row.component.ts

@ -38,7 +38,6 @@ import { merge } from 'rxjs';
@Component({
selector: 'tb-axis-scale-row',
templateUrl: './axis-scale-row.component.html',
styleUrl: './axis-scale-row.component.scss',
providers: [
{
provide: NG_VALUE_ACCESSOR,
@ -101,7 +100,6 @@ export class AxisScaleRowComponent implements ControlValueAccessor, OnInit, Vali
});
this.latestKeyFormControl = this.fb.control(null, [Validators.required]);
this.entityKeyFormControl = this.fb.control(null, [Validators.required]);
this.subscribeToTypeChanges();
merge(
this.latestKeyFormControl.valueChanges,
this.entityKeyFormControl.valueChanges,
@ -150,43 +148,25 @@ export class AxisScaleRowComponent implements ControlValueAccessor, OnInit, Vali
const errors: any = {};
if (this.limitForm.invalid) {
errors.form = this.getFormErrors();
errors.form = false;
}
if (type === ValueSourceType.latestKey) {
if (!this.latestKeyFormControl.value || this.latestKeyFormControl.invalid) {
errors.latestKey = {
valid: false
};
errors.latestKey = false;
}
} else if (type === ValueSourceType.entity) {
if (!this.limitForm.get('entityAlias')?.value) {
errors.entityAlias = {
valid: false
};
errors.entityAlias = false;
}
if (!this.entityKeyFormControl.value || this.entityKeyFormControl.invalid) {
errors.entityKey = {
valid: false
};
errors.entityKey = false;
}
}
return Object.keys(errors).length ? { axisLimitForm: errors } : null;
}
private getFormErrors(): any {
const errors: any = {};
Object.keys(this.limitForm.controls).forEach(key => {
const control = this.limitForm.get(key);
if (control && control.errors) {
errors[key] = control.errors;
}
});
return errors;
}
private updateValidators() {
const axisTypeControl = this.limitForm.get('type');
if (axisTypeControl && this.entityKeyFormControl && this.latestKeyFormControl) {
@ -207,38 +187,23 @@ export class AxisScaleRowComponent implements ControlValueAccessor, OnInit, Vali
}
}
private subscribeToTypeChanges() {
this.limitForm.controls.type.valueChanges
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
const axisValueControl = this.limitForm.get('value');
const axisEntityAliasControl = this.limitForm.get('entityAlias');
if (axisValueControl) {
axisValueControl.setValue(null, { emitEvent: false });
}
if (axisEntityAliasControl) {
axisEntityAliasControl.setValue(null, { emitEvent: false });
}
this.latestKeyFormControl.setValue(null, { emitEvent: false });
this.entityKeyFormControl.setValue(null, { emitEvent: false });
});
}
private updateModel() {
const value = this.limitForm.value;
this.modelValue.type = value.type ?? ValueSourceType.constant;
this.modelValue.value = value?.value;
this.modelValue.entityAlias = value?.entityAlias;
if (value.type === ValueSourceType.latestKey) {
const type = value.type;
let updates: Partial<ValueSourceConfig> = { type };
if (type === ValueSourceType.latestKey) {
const latestKey: DataKey = this.latestKeyFormControl.value;
this.modelValue.latestKey = latestKey?.name;
this.modelValue.latestKeyType = (latestKey?.type as any);
} else if (value.type === ValueSourceType.entity) {
updates.latestKey = latestKey?.name;
updates.latestKeyType = latestKey?.type as any;
} else if (type === ValueSourceType.entity) {
const entityKey: DataKey = this.entityKeyFormControl.value;
this.modelValue.entityKey = entityKey?.name;
this.modelValue.entityKeyType = (entityKey?.type as any);
updates.entityKey = entityKey?.name;
updates.entityKeyType = entityKey?.type as any;
updates.entityAlias = value?.entityAlias;
} else {
updates.value = value?.value;
}
this.modelValue = updates as ValueSourceConfig;
this.propagateChanges(this.modelValue);
}
}

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

@ -168,10 +168,7 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu
validate(): ValidationErrors | null {
return this.axisSettingsFormGroup.valid ? null : {
axisSettings: {
valid: false,
errors: this.getFormErrors()
}
axisSettings: false
};
}
@ -250,17 +247,6 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu
}
}
private getFormErrors(): any {
const errors: any = {};
Object.keys(this.axisSettingsFormGroup.controls).forEach(key => {
const control = this.axisSettingsFormGroup.get(key);
if (control && control.errors) {
errors[key] = control.errors;
}
});
return errors;
}
private updateModel() {
this.modelValue = this.axisSettingsFormGroup.getRawValue();
this.propagateChange(this.modelValue);

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

@ -196,6 +196,8 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
const axes: TimeSeriesChartYAxisSettings[] = this.yAxesFormGroup.get('axes').value;
axis.id = getNextTimeSeriesYAxisId(axes);
axis.order = axes.length;
axis.min = this.normalizeAxisLimit(axis.min);
axis.max = this.normalizeAxisLimit(axis.max);
const axesArray = this.yAxesFormGroup.get('axes') as UntypedFormArray;
const axisControl = this.fb.control(axis, [timeSeriesChartYAxisValidator]);
axesArray.push(axisControl);
@ -204,8 +206,6 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
private prepareAxesFormArray(axes: TimeSeriesChartYAxisSettings[]): UntypedFormArray {
const axesControls: Array<AbstractControl> = [];
axes.forEach((axis) => {
axis.min = this.normalizeAxisLimit(axis.min);
axis.max = this.normalizeAxisLimit(axis.max);
axesControls.push(this.fb.control(axis, [timeSeriesChartYAxisValidator]));
});
return this.fb.array(axesControls);
@ -216,17 +216,20 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
const result: TimeSeriesChartYAxes = {};
for (const [id, axis] of Object.entries(yAxes)) {
axis.min = this.normalizeAxisLimit(axis.min);
axis.max = this.normalizeAxisLimit(axis.max);
const minCfg = axis.min;
const maxCfg = axis.max;
const minCfg = axis.min as unknown as ValueSourceConfig;
const maxCfg = axis.max as unknown as ValueSourceConfig;
const minValid =
minCfg?.type !== ValueSourceType.latestKey ||
latestKeys.some(k => this.isYAxisKey(k, minCfg));
const minValid = !!minCfg && (
minCfg.type !== ValueSourceType.latestKey ||
latestKeys.some(k => this.isYAxisKey(k, minCfg))
);
const maxValid =
maxCfg?.type !== ValueSourceType.latestKey ||
latestKeys.some(k => this.isYAxisKey(k, maxCfg));
const maxValid = !!maxCfg && (
maxCfg.type !== ValueSourceType.latestKey ||
latestKeys.some(k => this.isYAxisKey(k, maxCfg))
);
if (minValid && maxValid) {
result[id] = axis;
@ -288,17 +291,17 @@ export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor,
d.type === limit.latestKeyType);
}
private normalizeAxisLimit(limit: any): ValueSourceConfig {
private normalizeAxisLimit(limit: string | number | ValueSourceConfig): ValueSourceConfig {
if (!limit) {
return {
type: ValueSourceType.constant,
value: null,
entityAlias: null
};
} else if (typeof limit === 'number') {
} else if (typeof limit === 'number' || typeof limit === 'string') {
return {
type: ValueSourceType.constant,
value: limit,
value: Number(limit),
entityAlias: null
};
}

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

@ -30,14 +30,16 @@
</mat-option>
</mat-select>
</mat-form-field>
<div class="tb-min-field">
<div class="tb-min-field" formGroupName="min">
<mat-form-field appearance="outline" class="tb-inline-field number" subscriptSizing="dynamic">
<input matInput formControlName="min" type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
<input matInput formControlName="value" type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}"
[disabled]="!checkIsConstantLimit('min')">
</mat-form-field>
</div>
<div class="tb-max-field">
<div class="tb-max-field" formGroupName="max">
<mat-form-field appearance="outline" class="tb-inline-field number" subscriptSizing="dynamic">
<input matInput formControlName="max" type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
<input matInput formControlName="value" type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}"
[disabled]="!checkIsConstantLimit('max')">
</mat-form-field>
</div>
<div class="tb-units-field">

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

@ -43,6 +43,7 @@ import { deepClone } from '@core/utils';
import { TranslateService } from '@ngx-translate/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { TimeSeriesChartYAxesPanelComponent } from '@home/components/widget/lib/settings/common/chart/time-series-chart-y-axes-panel.component';
import { ValueSourceType } from '@shared/models/widget-settings.models';
@Component({
selector: 'tb-time-series-chart-y-axis-row',
@ -99,8 +100,8 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
position: [null, []],
units: [null, []],
decimals: [null, []],
min: [null, []],
max: [null, []],
min: this.createLimitFormGroup(),
max: this.createLimitFormGroup(),
show: [null, []]
});
this.axisFormGroup.valueChanges.pipe(
@ -195,6 +196,10 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
}
}
checkIsConstantLimit(limit: 'min' | 'max') {
return this.axisFormGroup.get(`${limit}.type`)?.value === ValueSourceType.constant;
}
private updateValidators() {
const show: boolean = this.axisFormGroup.get('show').value;
if (show) {
@ -208,6 +213,13 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
this.axisFormGroup.get('units').disable({emitEvent: false});
this.axisFormGroup.get('decimals').disable({emitEvent: false});
}
if(!this.checkIsConstantLimit('min')){
this.axisFormGroup.get('min').disable({emitEvent: false});
}
if(!this.checkIsConstantLimit('max')){
this.axisFormGroup.get('max').disable({emitEvent: false});
}
}
private updateModel() {
@ -221,4 +233,12 @@ export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, O
this.modelValue.show = value.show;
this.propagateChange(this.modelValue);
}
private createLimitFormGroup() {
return this.fb.group({
type: [ValueSourceType.constant, []],
value: [null, []],
entityAlias: [null, []]
})
}
}

Loading…
Cancel
Save