Timewindow: aggregation type select component introduced
This commit is contained in:
parent
b09266a54c
commit
6991acd42c
@ -333,11 +333,12 @@ import * as AssetProfileComponent from '@home/components/profile/asset-profile.c
|
|||||||
import * as AssetProfileDialogComponent from '@home/components/profile/asset-profile-dialog.component';
|
import * as AssetProfileDialogComponent from '@home/components/profile/asset-profile-dialog.component';
|
||||||
import * as AssetProfileAutocompleteComponent from '@home/components/profile/asset-profile-autocomplete.component';
|
import * as AssetProfileAutocompleteComponent from '@home/components/profile/asset-profile-autocomplete.component';
|
||||||
import * as RuleChainSelectComponent from '@shared/components/rule-chain/rule-chain-select.component';
|
import * as RuleChainSelectComponent from '@shared/components/rule-chain/rule-chain-select.component';
|
||||||
|
import * as TimezoneComponent from '@shared/components/time/timezone.component';
|
||||||
|
import * as TimezonePanelComponent from '@shared/components/time/timezone-panel.component';
|
||||||
|
import * as DatapointsLimitComponent from '@shared/components/time/datapoints-limit.component';
|
||||||
|
import * as AggregationTypeSelectComponent from '@shared/components/aggregation/aggregation-type-select.component';
|
||||||
|
|
||||||
import { IModulesMap } from '@modules/common/modules-map.models';
|
import { IModulesMap } from '@modules/common/modules-map.models';
|
||||||
import { TimezoneComponent } from '@shared/components/time/timezone.component';
|
|
||||||
import { TimezonePanelComponent } from '@shared/components/time/timezone-panel.component';
|
|
||||||
import { DatapointsLimitComponent } from '@shared/components/time/datapoints-limit.component';
|
|
||||||
|
|
||||||
class ModulesMap implements IModulesMap {
|
class ModulesMap implements IModulesMap {
|
||||||
|
|
||||||
@ -470,6 +471,7 @@ class ModulesMap implements IModulesMap {
|
|||||||
'@shared/components/time/timezone.component': TimezoneComponent,
|
'@shared/components/time/timezone.component': TimezoneComponent,
|
||||||
'@shared/components/time/timezone-panel.component': TimezonePanelComponent,
|
'@shared/components/time/timezone-panel.component': TimezonePanelComponent,
|
||||||
'@shared/components/time/datapoints-limit': DatapointsLimitComponent,
|
'@shared/components/time/datapoints-limit': DatapointsLimitComponent,
|
||||||
|
'@shared/components/aggregation/aggregation-type-select': AggregationTypeSelectComponent,
|
||||||
'@shared/components/value-input.component': ValueInputComponent,
|
'@shared/components/value-input.component': ValueInputComponent,
|
||||||
'@shared/components/dashboard-autocomplete.component': DashboardAutocompleteComponent,
|
'@shared/components/dashboard-autocomplete.component': DashboardAutocompleteComponent,
|
||||||
'@shared/components/entity/entity-subtype-autocomplete.component': EntitySubTypeAutocompleteComponent,
|
'@shared/components/entity/entity-subtype-autocomplete.component': EntitySubTypeAutocompleteComponent,
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<mat-form-field [formGroup]="aggregationTypeFormGroup" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
|
||||||
|
<mat-label *ngIf="displayLabel">{{ label }}</mat-label>
|
||||||
|
<mat-select [required]="required" formControlName="aggregationType">
|
||||||
|
<mat-option *ngFor="let type of aggregationTypes" [value]="type">
|
||||||
|
{{ displayAggregationTypeFn(type) }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
:host {
|
||||||
|
.mat-mdc-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep {
|
||||||
|
.mat-mdc-form-field-infix {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.mat-mdc-select-value {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,155 @@
|
|||||||
|
///
|
||||||
|
/// 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, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||||
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||||
|
import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field';
|
||||||
|
import { aggregationTranslations, AggregationType } from '@shared/models/time/time.models';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-aggregation-type-select',
|
||||||
|
templateUrl: './aggregation-type-select.component.html',
|
||||||
|
styleUrls: ['./aggregation-type-select.component.scss'],
|
||||||
|
providers: [{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => AggregationTypeSelectComponent),
|
||||||
|
multi: true
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
export class AggregationTypeSelectComponent implements ControlValueAccessor, OnInit, OnChanges {
|
||||||
|
|
||||||
|
aggregationTypeFormGroup: FormGroup;
|
||||||
|
|
||||||
|
modelValue: AggregationType | null;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
allowedAggregationTypes: Array<AggregationType>;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
required: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
displayLabel = true;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
labelText: string;
|
||||||
|
|
||||||
|
get label(): string {
|
||||||
|
if (this.labelText && this.labelText.length) {
|
||||||
|
return this.labelText;
|
||||||
|
}
|
||||||
|
return this.defaultLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
subscriptSizing: SubscriptSizing = 'fixed';
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
appearance: MatFormFieldAppearance = 'fill';
|
||||||
|
|
||||||
|
aggregationTypes: Array<AggregationType>;
|
||||||
|
|
||||||
|
private defaultLabel = this.translate.instant('aggregation.aggregation');
|
||||||
|
|
||||||
|
private allAggregationTypes: Array<AggregationType> = Object.values(AggregationType);
|
||||||
|
|
||||||
|
private propagateChange = (v: any) => { };
|
||||||
|
|
||||||
|
constructor(private translate: TranslateService,
|
||||||
|
private fb: FormBuilder) {
|
||||||
|
this.aggregationTypeFormGroup = this.fb.group({
|
||||||
|
aggregationType: [null]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.aggregationTypes = this.allowedAggregationTypes?.length ? this.allowedAggregationTypes : this.allAggregationTypes;
|
||||||
|
this.aggregationTypeFormGroup.get('aggregationType').valueChanges.subscribe(
|
||||||
|
(value) => {
|
||||||
|
let modelValue;
|
||||||
|
if (!value || value === '') {
|
||||||
|
modelValue = null;
|
||||||
|
} else {
|
||||||
|
modelValue = value;
|
||||||
|
}
|
||||||
|
this.updateView(modelValue);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
for (const propName of Object.keys(changes)) {
|
||||||
|
const change = changes[propName];
|
||||||
|
if (!change.firstChange && change.currentValue !== change.previousValue) {
|
||||||
|
if (propName === 'allowedAggregationTypes') {
|
||||||
|
this.aggregationTypes = this.allowedAggregationTypes?.length ? this.allowedAggregationTypes : this.allAggregationTypes;
|
||||||
|
const currentAggregationType: AggregationType = this.aggregationTypeFormGroup.get('aggregationType').value;
|
||||||
|
if (currentAggregationType && !this.aggregationTypes.includes(currentAggregationType)) {
|
||||||
|
this.aggregationTypeFormGroup.get('aggregationType').patchValue(null, {emitEvent: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
if (this.disabled) {
|
||||||
|
this.aggregationTypeFormGroup.disable();
|
||||||
|
} else {
|
||||||
|
this.aggregationTypeFormGroup.enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: AggregationType | null): void {
|
||||||
|
if (value != null) {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.aggregationTypeFormGroup.get('aggregationType').patchValue(value, {emitEvent: true});
|
||||||
|
} else {
|
||||||
|
this.modelValue = null;
|
||||||
|
this.aggregationTypeFormGroup.get('aggregationType').patchValue(null, {emitEvent: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateView(value: AggregationType | null) {
|
||||||
|
if (this.modelValue !== value) {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.propagateChange(this.modelValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayAggregationTypeFn(aggregationType?: AggregationType | null): string | undefined {
|
||||||
|
if (aggregationType) {
|
||||||
|
return this.translate.instant(aggregationTranslations.get(aggregationType));
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -167,13 +167,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
<ng-container formGroupName="aggregation">
|
<ng-container formGroupName="aggregation">
|
||||||
<mat-form-field class="flex" subscriptSizing="dynamic" appearance="outline">
|
<tb-aggregation-type-select class="flex" subscriptSizing="dynamic" appearance="outline" displayLabel="false"
|
||||||
<mat-select formControlName="type">
|
formControlName="type">
|
||||||
<mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">
|
</tb-aggregation-type-select>
|
||||||
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -66,10 +66,6 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On
|
|||||||
|
|
||||||
aggregationTypes = AggregationType;
|
aggregationTypes = AggregationType;
|
||||||
|
|
||||||
aggregations = Object.keys(AggregationType);
|
|
||||||
|
|
||||||
aggregationTypesTranslations = aggregationTranslations;
|
|
||||||
|
|
||||||
result: Timewindow;
|
result: Timewindow;
|
||||||
|
|
||||||
timewindowTypeOptions: ToggleHeaderOption[] = [
|
timewindowTypeOptions: ToggleHeaderOption[] = [
|
||||||
|
|||||||
@ -30,7 +30,8 @@
|
|||||||
tb-timeinterval,
|
tb-timeinterval,
|
||||||
tb-quick-time-interval,
|
tb-quick-time-interval,
|
||||||
tb-datetime-period,
|
tb-datetime-period,
|
||||||
tb-datapoints-limit {
|
tb-datapoints-limit,
|
||||||
|
tb-aggregation-type-select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,20 +125,16 @@
|
|||||||
<ng-container formGroupName="aggregation">
|
<ng-container formGroupName="aggregation">
|
||||||
<section class="tb-form-row column-xs space-between same-padding" *ngIf="isEdit || !timewindow.hideAggregation">
|
<section class="tb-form-row column-xs space-between same-padding" *ngIf="isEdit || !timewindow.hideAggregation">
|
||||||
<div class="fixed-title-width-180">{{ 'aggregation.aggregation' | translate }}</div>
|
<div class="fixed-title-width-180">{{ 'aggregation.aggregation' | translate }}</div>
|
||||||
<mat-form-field class="flex" subscriptSizing="dynamic" appearance="outline">
|
<tb-aggregation-type-select class="flex" subscriptSizing="dynamic" appearance="outline" displayLabel="false"
|
||||||
<mat-select formControlName="type">
|
formControlName="type">
|
||||||
<mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">
|
</tb-aggregation-type-select>
|
||||||
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="tb-form-row column-xs space-between same-padding"
|
<section class="tb-form-row column-xs space-between same-padding"
|
||||||
*ngIf="timewindowForm.get('aggregation.type').value === aggregationTypes.NONE && (isEdit || !timewindow.hideAggInterval)">
|
*ngIf="timewindowForm.get('aggregation.type').value === aggregationTypes.NONE && (isEdit || !timewindow.hideAggInterval)">
|
||||||
<div>{{ 'aggregation.limit' | translate }}</div>
|
<div>{{ 'aggregation.limit' | translate }}</div>
|
||||||
<tb-datapoints-limit formControlName="limit"
|
<tb-datapoints-limit formControlName="limit"
|
||||||
[required]="timewindowForm.get('aggregation.type').value === aggregationTypes.NONE">
|
[required]="timewindowForm.get('aggregation.type').value === aggregationTypes.MIN">
|
||||||
</tb-datapoints-limit>
|
</tb-datapoints-limit>
|
||||||
</section>
|
</section>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -87,10 +87,6 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O
|
|||||||
|
|
||||||
aggregationTypes = AggregationType;
|
aggregationTypes = AggregationType;
|
||||||
|
|
||||||
aggregations = Object.keys(AggregationType);
|
|
||||||
|
|
||||||
aggregationTypesTranslations = aggregationTranslations;
|
|
||||||
|
|
||||||
result: Timewindow;
|
result: Timewindow;
|
||||||
|
|
||||||
timewindowTypeOptions: ToggleHeaderOption[] = [{
|
timewindowTypeOptions: ToggleHeaderOption[] = [{
|
||||||
@ -517,4 +513,6 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected readonly AggregationType = AggregationType;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -230,6 +230,7 @@ import { CountryAutocompleteComponent } from '@shared/components/country-autocom
|
|||||||
import { CountryData } from '@shared/models/country.models';
|
import { CountryData } from '@shared/models/country.models';
|
||||||
import { SvgXmlComponent } from '@shared/components/svg-xml.component';
|
import { SvgXmlComponent } from '@shared/components/svg-xml.component';
|
||||||
import { DatapointsLimitComponent } from '@shared/components/time/datapoints-limit.component';
|
import { DatapointsLimitComponent } from '@shared/components/time/datapoints-limit.component';
|
||||||
|
import { AggregationTypeSelectComponent } from '@shared/components/aggregation/aggregation-type-select.component';
|
||||||
|
|
||||||
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
|
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
|
||||||
return markedOptionsService;
|
return markedOptionsService;
|
||||||
@ -320,6 +321,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
TimezonePanelComponent,
|
TimezonePanelComponent,
|
||||||
QuickTimeIntervalComponent,
|
QuickTimeIntervalComponent,
|
||||||
DatapointsLimitComponent,
|
DatapointsLimitComponent,
|
||||||
|
AggregationTypeSelectComponent,
|
||||||
DashboardSelectComponent,
|
DashboardSelectComponent,
|
||||||
DashboardSelectPanelComponent,
|
DashboardSelectPanelComponent,
|
||||||
DatetimePeriodComponent,
|
DatetimePeriodComponent,
|
||||||
@ -536,6 +538,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
TimezonePanelComponent,
|
TimezonePanelComponent,
|
||||||
QuickTimeIntervalComponent,
|
QuickTimeIntervalComponent,
|
||||||
DatapointsLimitComponent,
|
DatapointsLimitComponent,
|
||||||
|
AggregationTypeSelectComponent,
|
||||||
DashboardSelectComponent,
|
DashboardSelectComponent,
|
||||||
DatetimePeriodComponent,
|
DatetimePeriodComponent,
|
||||||
DatetimeComponent,
|
DatetimeComponent,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user