From 5ff73e97fc873cc2d100b6f278a8106f01abc1bc Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Mon, 25 Nov 2024 19:03:15 +0200 Subject: [PATCH] Timewindow: group intervals configuration scratch --- ui-ngx/src/app/modules/common/modules-map.ts | 2 + ...terval-options-config-panel.component.html | 36 +++-- ...terval-options-config-panel.component.scss | 10 ++ ...interval-options-config-panel.component.ts | 30 ++-- .../time/quick-time-interval.component.ts | 2 +- .../time/time-intervals-list.component.html | 27 ++++ .../time/time-intervals-list.component.scss | 25 +++ .../time/time-intervals-list.component.ts | 147 ++++++++++++++++++ .../components/time/timeinterval.component.ts | 4 - ui-ngx/src/app/shared/shared.module.ts | 3 + .../assets/locale/locale.constant-en_US.json | 2 +- ui-ngx/src/form.scss | 11 ++ 12 files changed, 263 insertions(+), 36 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/time/time-intervals-list.component.html create mode 100644 ui-ngx/src/app/shared/components/time/time-intervals-list.component.scss create mode 100644 ui-ngx/src/app/shared/components/time/time-intervals-list.component.ts diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 64a44516df..822f92b211 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -337,6 +337,7 @@ import * as DatapointsLimitComponent from '@shared/components/time/datapoints-li import * as AggregationTypeSelectComponent from '@shared/components/time/aggregation/aggregation-type-select.component'; import * as AggregationOptionsConfigComponent from '@shared/components/time/aggregation/aggregation-options-config-panel.component'; import * as IntervalOptionsConfigPanelComponent from '@shared/components/time/interval-options-config-panel.component'; +import * as TimeIntervalsListComponent from '@shared/components/time/time-intervals-list.component'; import { IModulesMap } from '@modules/common/modules-map.models'; import { Observable, map, of } from 'rxjs'; @@ -476,6 +477,7 @@ class ModulesMap implements IModulesMap { '@shared/components/time/aggregation/aggregation-type-select.component': AggregationTypeSelectComponent, '@shared/components/time/aggregation/aggregation-options-config-panel.component': AggregationOptionsConfigComponent, '@shared/components/time/interval-options-config-panel.component': IntervalOptionsConfigPanelComponent, + '@shared/components/time/time-intervals-list.component': TimeIntervalsListComponent, '@shared/components/value-input.component': ValueInputComponent, '@shared/components/dashboard-autocomplete.component': DashboardAutocompleteComponent, '@shared/components/entity/entity-subtype-autocomplete.component': EntitySubTypeAutocompleteComponent, diff --git a/ui-ngx/src/app/shared/components/time/interval-options-config-panel.component.html b/ui-ngx/src/app/shared/components/time/interval-options-config-panel.component.html index b99da0d5af..8368ce29af 100644 --- a/ui-ngx/src/app/shared/components/time/interval-options-config-panel.component.html +++ b/ui-ngx/src/app/shared/components/time/interval-options-config-panel.component.html @@ -21,32 +21,40 @@
{{ 'timewindow.edit-intervals-list-hint' | translate }} {{ aggregation ? ('timewindow.edit-grouping-intervals-list-hint' | translate) : '' }}
-
+
-
{{"timewindow.interval" | translate }}
+
{{"timewindow.interval" | translate }}
-
{{"timewindow.allowed-agg-intervals" | translate }}
-
{{"timewindow.preferred-agg-interval" | translate }}
+
{{"timewindow.allowed-agg-intervals" | translate }}
+
{{"timewindow.preferred-agg-interval" | translate }}
-
- - - - - +
-
+
{{ interval.get('name').value }}
-
-
+
+ + +
+
= []; - for (const interval of this.allIntervals) { - const intervalConfig: TimewindowAllowedAggIntervalOption = this.allowedAggIntervals?.hasOwnProperty(interval.value) - ? this.allIntervalValues[interval.value] - : null; - intervalControls.push(this.fb.group({ - name: [this.translate.instant(interval.name, interval.translateParams)], - value: [interval.value], - enabled: [this.allowedIntervals?.length ? this.allowedIntervals.includes(interval.value) : true], - aggIntervals: [intervalConfig ? intervalConfig.aggIntervals : []], - preferredAggInterval: [intervalConfig ? intervalConfig.preferredAggInterval : null] - })); - } - this.intervalOptionsConfigForm.setControl('intervals', this.fb.array(intervalControls), {emitEvent: false}); + const intervalControls: Array = []; + for (const interval of this.allIntervals) { + const intervalConfig: TimewindowAllowedAggIntervalOption = this.allowedAggIntervals?.hasOwnProperty(interval.value) + ? this.allIntervalValues[interval.value] + : null; + intervalControls.push(this.fb.group({ + name: [this.translate.instant(interval.name, interval.translateParams)], + value: [interval.value], + enabled: [this.allowedIntervals?.length ? this.allowedIntervals.includes(interval.value) : true], + aggIntervals: [intervalConfig ? intervalConfig.aggIntervals : []], + preferredAggInterval: [intervalConfig ? intervalConfig.preferredAggInterval : null] + })); } + this.intervalOptionsConfigForm.setControl('intervals', this.fb.array(intervalControls), {emitEvent: false}); } get intervalsFormArray(): UntypedFormArray { @@ -151,7 +149,7 @@ export class IntervalOptionsConfigPanelComponent implements OnInit { this.intervalOptionsConfigForm.markAsDirty(); } - private getQuickIntervals() { + private getQuickIntervals(): Array { const allQuickIntervals = Object.values(QuickTimeInterval); if (this.timewindowType === TimewindowType.REALTIME) { return allQuickIntervals.filter(interval => interval.startsWith('CURRENT_')); diff --git a/ui-ngx/src/app/shared/components/time/quick-time-interval.component.ts b/ui-ngx/src/app/shared/components/time/quick-time-interval.component.ts index 4b322718ea..2117ed6f67 100644 --- a/ui-ngx/src/app/shared/components/time/quick-time-interval.component.ts +++ b/ui-ngx/src/app/shared/components/time/quick-time-interval.component.ts @@ -36,7 +36,7 @@ import { isEqual } from '@core/utils'; }) export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor, OnChanges { - private allIntervals = Object.values(QuickTimeInterval); + private allIntervals = Object.values(QuickTimeInterval) as QuickTimeInterval[]; modelValue: QuickTimeInterval; timeIntervalTranslationMap = QuickTimeIntervalTranslationMap; diff --git a/ui-ngx/src/app/shared/components/time/time-intervals-list.component.html b/ui-ngx/src/app/shared/components/time/time-intervals-list.component.html new file mode 100644 index 0000000000..d6f101c030 --- /dev/null +++ b/ui-ngx/src/app/shared/components/time/time-intervals-list.component.html @@ -0,0 +1,27 @@ + +
+ + {{ predefinedName }} + + + {{ interval.name | translate:interval.translateParams }} + + + +
diff --git a/ui-ngx/src/app/shared/components/time/time-intervals-list.component.scss b/ui-ngx/src/app/shared/components/time/time-intervals-list.component.scss new file mode 100644 index 0000000000..1fb09c65f5 --- /dev/null +++ b/ui-ngx/src/app/shared/components/time/time-intervals-list.component.scss @@ -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. + */ +@import '../../../../scss/constants'; + +:host { + + @media #{$mat-xs} { + min-width: 0; + width: 100%; + } +} + diff --git a/ui-ngx/src/app/shared/components/time/time-intervals-list.component.ts b/ui-ngx/src/app/shared/components/time/time-intervals-list.component.ts new file mode 100644 index 0000000000..4deba4a271 --- /dev/null +++ b/ui-ngx/src/app/shared/components/time/time-intervals-list.component.ts @@ -0,0 +1,147 @@ +/// +/// 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 } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { TimeService } from '@core/services/time.service'; +import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field'; +import { coerceBoolean, coerceNumber } from '@shared/decorators/coercion'; +import { Interval, TimeInterval } from '@shared/models/time/time.models'; +import { isDefined } from '@core/utils'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; + +@Component({ + selector: 'tb-time-intervals-list', + templateUrl: './time-intervals-list.component.html', + styleUrls: ['./time-intervals-list.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TimeIntervalsListComponent), + multi: true + } + ] +}) +export class TimeIntervalsListComponent implements OnInit, ControlValueAccessor { + + @Input() + @coerceNumber() + min: number; + + @Input() + @coerceNumber() + max: number; + + @Input() predefinedName: string; + + @Input() + @coerceBoolean() + setAllIfEmpty = false; + + @Input() + @coerceBoolean() + returnEmptyIfAllSet = false; + + @Input() + @coerceBoolean() + useCalendarIntervals = false; + + @Input() disabled: boolean; + + @Input() + subscriptSizing: SubscriptSizing = 'fixed'; + + @Input() + appearance: MatFormFieldAppearance = 'fill'; + + intervals: Array; + + timeintervalFormGroup: FormGroup; + + private modelValue: Array; + private rendered = false; + private propagateChangeValue: any; + + private propagateChange = (value: any) => { + this.propagateChangeValue = value; + }; + + constructor(private timeService: TimeService, + private fb: FormBuilder) { + this.timeintervalFormGroup = this.fb.group({ + intervals: [ [] ] + }); + this.timeintervalFormGroup.get('intervals').valueChanges.pipe( + takeUntilDestroyed() + ).subscribe(() => this.updateView()); + } + + ngOnInit(): void { + this.updateIntervalsList(); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + if (isDefined(this.propagateChangeValue)) { + this.propagateChange(this.propagateChangeValue); + } + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.timeintervalFormGroup.disable({emitEvent: false}); + } else { + this.timeintervalFormGroup.enable({emitEvent: false}); + } + } + + writeValue(intervals: Array): void { + this.modelValue = intervals; + this.rendered = true; + this.setIntervals(this.modelValue); + } + + private updateIntervalsList() { + this.intervals = this.timeService.getIntervals(this.min, this.max, this.useCalendarIntervals); + } + + private setIntervals(intervals: Array) { + this.timeintervalFormGroup.get('intervals').patchValue( + (this.setAllIfEmpty && !intervals?.length) ? this.intervals : intervals, + {emitEvent: false}); + } + + private updateView() { + if (!this.rendered) { + return; + } + let value: Array; + const intervals: Array = this.timeintervalFormGroup.get('intervals').value; + + if (!this.returnEmptyIfAllSet || intervals.length < this.intervals.length) { + value = intervals; + } else { + value = []; + } + this.modelValue = value; + this.propagateChange(this.modelValue); + } + +} diff --git a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts index 2446923f3e..a7229660d5 100644 --- a/ui-ngx/src/app/shared/components/time/timeinterval.component.ts +++ b/ui-ngx/src/app/shared/components/time/timeinterval.component.ts @@ -74,10 +74,6 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor, OnCh @Input() predefinedName: string; - @Input() - @coerceBoolean() - isEdit = false; - @Input({transform : booleanAttribute}) disabledAdvanced = false; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index be4e32c3a0..5f4f5deba7 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -221,6 +221,7 @@ import { DatapointsLimitComponent } from '@shared/components/time/datapoints-lim import { AggregationTypeSelectComponent } from '@shared/components/time/aggregation/aggregation-type-select.component'; import { AggregationOptionsConfigPanelComponent } from '@shared/components/time/aggregation/aggregation-options-config-panel.component'; import { IntervalOptionsConfigPanelComponent } from '@shared/components/time/interval-options-config-panel.component'; +import { TimeIntervalsListComponent } from '@shared/components/time/time-intervals-list.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -306,6 +307,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) TimewindowPanelComponent, TimewindowConfigDialogComponent, TimeintervalComponent, + TimeIntervalsListComponent, TimezoneComponent, TimezonePanelComponent, QuickTimeIntervalComponent, @@ -516,6 +518,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) TimewindowPanelComponent, TimewindowConfigDialogComponent, TimeintervalComponent, + TimeIntervalsListComponent, TimezoneComponent, TimezonePanelComponent, QuickTimeIntervalComponent, diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 20b67af14b..7e7e75353d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4548,7 +4548,7 @@ "edit-aggregation-functions-list-hint": "List of available options can be specified.", "allowed-aggregation-functions": "Allowed aggregation functions", "edit-intervals-list": "Edit intervals list", - "allowed-agg-intervals": "Allowed aggregation intervals", + "allowed-agg-intervals": "Allowed grouping intervals", "preferred-agg-interval": "Preferred intervals", "edit-intervals-list-hint": "List of available interval options can be specified.", "edit-grouping-intervals-list-hint": "It is possible to configure the grouping intervals list and default grouping interval." diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index bd3ba3c275..9ed6cec2e8 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -799,4 +799,15 @@ } } } + + .mat-mdc-form-field-has-icon-suffix { + .mat-mdc-form-field-icon-suffix:empty { + padding: 0; + } + .mat-mdc-text-field-wrapper:has(.mat-mdc-form-field-icon-suffix:empty) { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-right: 16px; + } + } + } }