Browse Source

UI: timeinterval component redesign

pull/11633/head
Chantsova Ekaterina 2 years ago
parent
commit
399bfb8dbd
  1. 54
      ui-ngx/src/app/shared/components/time/timeinterval.component.html
  2. 17
      ui-ngx/src/app/shared/components/time/timeinterval.component.scss
  3. 224
      ui-ngx/src/app/shared/components/time/timeinterval.component.ts
  4. 2
      ui-ngx/src/app/shared/components/time/timewindow-panel.component.html

54
ui-ngx/src/app/shared/components/time/timeinterval.component.html

@ -15,43 +15,37 @@
limitations under the License. limitations under the License.
--> -->
<section fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px"> <section class="tb-form-panel no-border no-padding" [formGroup]="timeintervalFormGroup">
<section fxLayout="column" fxLayoutAlign="start center" [fxShow]="isEdit"> <mat-form-field fxFlex [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<label class="tb-small hide-label" translate>timewindow.hide</label> <mat-label *ngIf="predefinedName" translate>{{ predefinedName }}</mat-label>
<mat-checkbox [(ngModel)]="hideFlag" (ngModelChange)="onHideFlagChange()"></mat-checkbox> <mat-select formControlName="interval">
</section> <mat-option *ngFor="let interval of intervals" [value]="interval.value">
<section class="interval-section" fxLayout="column" fxFlex fxLayoutGap="16px"> {{ interval.name | translate:interval.translateParams }}
<section fxLayout="row" fxFlex [fxShow]="isEdit || !hideFlag"> </mat-option>
<mat-form-field fxFlex [subscriptSizing]="subscriptSizing" [appearance]="appearance"> </mat-select>
<mat-label *ngIf="predefinedName" translate>{{ predefinedName }}</mat-label> </mat-form-field>
<mat-select [disabled]="hideFlag || disabled" [(ngModel)]="interval" (ngModelChange)="onIntervalChange()" style="min-width: 150px;"> <section class="tb-form-row column-xs no-border no-padding tb-standard-fields advanced-input"
<mat-option *ngFor="let interval of intervals" [value]="interval.value"> formGroupName="customInterval"
{{ interval.name | translate:interval.translateParams }} [fxShow]="advanced">
</mat-option> <div class="tb-flex">
</mat-select> <mat-form-field class="number-input flex" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
</mat-form-field>
</section>
<section fxLayout="row wrap" fxLayoutAlign="start start" fxFlex fxLayoutGap="6px" [fxShow]="advanced && (isEdit || !hideFlag)">
<mat-form-field class="number-input" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timeinterval.days</mat-label> <mat-label translate>timeinterval.days</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" min="0" [(ngModel)]="days" (ngModelChange)="onTimeInputChange('days')"/> <input matInput type="number" step="1" min="0" formControlName="days" />
</mat-form-field> </mat-form-field>
<mat-form-field class="number-input" [subscriptSizing]="subscriptSizing" [appearance]="appearance"> <mat-form-field class="number-input flex" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timeinterval.hours</mat-label> <mat-label translate>timeinterval.hours</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" [(ngModel)]="hours" (ngModelChange)="onTimeInputChange('hours')"/> <input matInput type="number" step="1" formControlName="hours" />
</mat-form-field> </mat-form-field>
<mat-form-field class="number-input" [subscriptSizing]="subscriptSizing" [appearance]="appearance"> </div>
<div class="tb-flex">
<mat-form-field class="number-input flex" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timeinterval.minutes</mat-label> <mat-label translate>timeinterval.minutes</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" [(ngModel)]="mins" (ngModelChange)="onTimeInputChange('mins')"/> <input matInput type="number" step="1" formControlName="mins" />
</mat-form-field> </mat-form-field>
<mat-form-field class="number-input" [subscriptSizing]="subscriptSizing" [appearance]="appearance"> <mat-form-field class="number-input flex" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timeinterval.seconds</mat-label> <mat-label translate>timeinterval.seconds</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" [(ngModel)]="secs" (ngModelChange)="onTimeInputChange('secs')"/> <input matInput type="number" step="1" formControlName="secs" />
</mat-form-field> </mat-form-field>
</section> </div>
</section>
<section fxLayout="column" fxLayoutAlign="center center" [fxShow]="(isEdit || !hideFlag) && !disabledAdvanced">
<label class="tb-small advanced-label" translate>timeinterval.advanced</label>
<mat-slide-toggle [disabled]="hideFlag || disabled" class="advanced-switch" [(ngModel)]="advanced" (ngModelChange)="onAdvancedChange()"></mat-slide-toggle>
</section> </section>
</section> </section>

17
ui-ngx/src/app/shared/components/time/timeinterval.component.scss

@ -18,22 +18,21 @@
:host { :host {
min-width: 355px; min-width: 355px;
.advanced-switch { .tb-form-panel {
margin-bottom: 16px; gap: 12px;
} }
.advanced-label { .advanced-input {
margin: 5px 0; gap: 8px;
}
.hide-label {
margin-bottom: 5px;
margin-right: 5px;
} }
@media #{$mat-xs} { @media #{$mat-xs} {
min-width: 0; min-width: 0;
width: 100%; width: 100%;
.advanced-input {
gap: 12px;
}
} }
} }

224
ui-ngx/src/app/shared/components/time/timeinterval.component.ts

@ -14,8 +14,8 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { TimeService } from '@core/services/time.service'; import { TimeService } from '@core/services/time.service';
import { coerceNumberProperty } from '@angular/cdk/coercion'; import { coerceNumberProperty } from '@angular/cdk/coercion';
import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field'; import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field';
@ -23,6 +23,8 @@ import { coerceBoolean } from '@shared/decorators/coercion';
import { Interval, IntervalMath, TimeInterval } from '@shared/models/time/time.models'; import { Interval, IntervalMath, TimeInterval } from '@shared/models/time/time.models';
import { isDefined } from '@core/utils'; import { isDefined } from '@core/utils';
import { IntervalType } from '@shared/models/telemetry/telemetry.models'; import { IntervalType } from '@shared/models/telemetry/telemetry.models';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
@Component({ @Component({
selector: 'tb-timeinterval', selector: 'tb-timeinterval',
@ -36,7 +38,7 @@ import { IntervalType } from '@shared/models/telemetry/telemetry.models';
} }
] ]
}) })
export class TimeintervalComponent implements OnInit, ControlValueAccessor { export class TimeintervalComponent implements OnInit, ControlValueAccessor, OnDestroy {
minValue: number; minValue: number;
maxValue: number; maxValue: number;
@ -67,10 +69,6 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
@coerceBoolean() @coerceBoolean()
isEdit = false; isEdit = false;
@Input()
@coerceBoolean()
hideFlag = false;
@Input() @Input()
@coerceBoolean() @coerceBoolean()
disabledAdvanced = false; disabledAdvanced = false;
@ -79,8 +77,6 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
@coerceBoolean() @coerceBoolean()
useCalendarIntervals = false; useCalendarIntervals = false;
@Output() hideFlagChange = new EventEmitter<boolean>();
@Input() disabled: boolean; @Input() disabled: boolean;
@Input() @Input()
@ -89,16 +85,12 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
@Input() @Input()
appearance: MatFormFieldAppearance = 'fill'; appearance: MatFormFieldAppearance = 'fill';
days = 0;
hours = 0;
mins = 1;
secs = 0;
interval: Interval = 0;
intervals: Array<TimeInterval>; intervals: Array<TimeInterval>;
advanced = false; advanced = false;
timeintervalFormGroup: FormGroup;
customTimeInterval: TimeInterval = { customTimeInterval: TimeInterval = {
name: 'timeinterval.custom', name: 'timeinterval.custom',
translateParams: {}, translateParams: {},
@ -113,7 +105,43 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
this.propagateChangeValue = value; this.propagateChangeValue = value;
}; };
constructor(private timeService: TimeService) { private destroy$ = new Subject<void>();
constructor(private timeService: TimeService,
private fb: FormBuilder) {
this.timeintervalFormGroup = this.fb.group({
interval: [ 1 ],
customInterval: this.fb.group({
days: [ 0 ],
hours: [ 0 ],
mins: [ 1 ],
secs: [ 0 ]
})
});
this.timeintervalFormGroup.get('interval').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => this.onIntervalChange());
this.timeintervalFormGroup.get('customInterval').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe(() => this.updateView());
this.timeintervalFormGroup.get('customInterval.secs').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((secs) => this.onSecsChange(secs));
this.timeintervalFormGroup.get('customInterval.mins').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((mins) => this.onMinsChange(mins));
this.timeintervalFormGroup.get('customInterval.hours').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((hours) => this.onHoursChange(hours));
this.timeintervalFormGroup.get('customInterval.days').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((days) => this.onDaysChange(days));
} }
ngOnInit(): void { ngOnInit(): void {
@ -132,6 +160,11 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
setDisabledState(isDisabled: boolean): void { setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled; this.disabled = isDisabled;
if (this.disabled) {
this.timeintervalFormGroup.disable({emitEvent: false});
} else {
this.timeintervalFormGroup.enable({emitEvent: false});
}
} }
writeValue(interval: Interval): void { writeValue(interval: Interval): void {
@ -156,20 +189,31 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
} }
private setInterval(interval: Interval) { private setInterval(interval: Interval) {
// if (!this.advanced) { if (!this.advanced) {
this.interval = interval; this.timeintervalFormGroup.get('interval').patchValue(interval);
// } } else {
this.timeintervalFormGroup.get('interval').patchValue(IntervalType.CUSTOM);
this.setCustomInterval(interval);
}
}
private setCustomInterval(interval: Interval) {
const intervalSeconds = Math.floor(IntervalMath.numberValue(interval) / 1000); const intervalSeconds = Math.floor(IntervalMath.numberValue(interval) / 1000);
this.days = Math.floor(intervalSeconds / 86400); this.timeintervalFormGroup.get('customInterval').patchValue({
this.hours = Math.floor((intervalSeconds % 86400) / 3600); days: Math.floor(intervalSeconds / 86400),
this.mins = Math.floor(((intervalSeconds % 86400) % 3600) / 60); hours: Math.floor((intervalSeconds % 86400) / 3600),
this.secs = intervalSeconds % 60; mins: Math.floor(((intervalSeconds % 86400) % 3600) / 60),
secs: intervalSeconds % 60
});
} }
private boundInterval(updateToPreferred = false) { private boundInterval(updateToPreferred = false) {
const min = this.timeService.boundMinInterval(this.minValue); const min = this.timeService.boundMinInterval(this.minValue);
const max = this.timeService.boundMaxInterval(this.maxValue); const max = this.timeService.boundMaxInterval(this.maxValue);
this.intervals = this.timeService.getIntervals(this.minValue, this.maxValue, this.useCalendarIntervals); this.intervals = this.timeService.getIntervals(this.minValue, this.maxValue, this.useCalendarIntervals);
if (!this.disabledAdvanced) {
this.intervals.push(this.customTimeInterval);
}
if (this.rendered) { if (this.rendered) {
let newInterval = this.modelValue; let newInterval = this.modelValue;
const newIntervalMs = IntervalMath.numberValue(newInterval); const newIntervalMs = IntervalMath.numberValue(newInterval);
@ -195,7 +239,7 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
let value: Interval = null; let value: Interval = null;
let interval: Interval; let interval: Interval;
if (!this.advanced) { if (!this.advanced) {
interval = this.interval; interval = this.timeintervalFormGroup.get('interval').value;
if (!interval || typeof interval === 'number' && isNaN(interval)) { if (!interval || typeof interval === 'number' && isNaN(interval)) {
interval = this.calculateIntervalMs(); interval = this.calculateIntervalMs();
} }
@ -211,118 +255,90 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
} }
private calculateIntervalMs(): number { private calculateIntervalMs(): number {
return (this.days * 86400 + const customInterval = this.timeintervalFormGroup.get('customInterval').value;
this.hours * 3600 + return (customInterval.days * 86400 +
this.mins * 60 + customInterval.hours * 3600 +
this.secs) * 1000; customInterval.mins * 60 +
customInterval.secs) * 1000;
} }
onIntervalChange() { onIntervalChange() {
this.updateView(); const customIntervalSelected = this.timeintervalFormGroup.get('interval').value === IntervalType.CUSTOM;
} if (customIntervalSelected !== this.advanced) {
this.advanced = customIntervalSelected;
onAdvancedChange() { if (this.advanced) {
if (!this.advanced) { this.setCustomInterval(this.modelValue);
this.interval = this.calculateIntervalMs();
} else {
let interval = this.interval;
if (!interval || typeof interval === 'number' && isNaN(interval)) {
interval = this.calculateIntervalMs();
} }
this.setInterval(interval);
} }
this.updateView(); this.updateView();
} }
onHideFlagChange() { private onSecsChange(secs: number) {
this.hideFlagChange.emit(this.hideFlag); const customInterval = this.timeintervalFormGroup.get('customInterval').value;
} if (typeof secs === 'undefined') {
onTimeInputChange(type: string) {
switch (type) {
case 'secs':
setTimeout(() => this.onSecsChange(), 0);
break;
case 'mins':
setTimeout(() => this.onMinsChange(), 0);
break;
case 'hours':
setTimeout(() => this.onHoursChange(), 0);
break;
case 'days':
setTimeout(() => this.onDaysChange(), 0);
break;
}
}
private onSecsChange() {
if (typeof this.secs === 'undefined') {
return; return;
} }
if (this.secs < 0) { if (secs < 0) {
if ((this.days + this.hours + this.mins) > 0) { if ((customInterval.days + customInterval.hours + customInterval.mins) > 0) {
this.secs = this.secs + 60; this.timeintervalFormGroup.get('customInterval.secs').patchValue(secs + 60, {emitEvent: false});
this.mins--; this.timeintervalFormGroup.get('customInterval.mins').patchValue(customInterval.mins - 1, {emitEvent: true});
this.onMinsChange();
} else { } else {
this.secs = 0; this.timeintervalFormGroup.get('customInterval.secs').patchValue(0, {emitEvent: false});
} }
} else if (this.secs >= 60) { } else if (secs >= 60) {
this.secs = this.secs - 60; this.timeintervalFormGroup.get('customInterval.secs').patchValue(secs - 60, {emitEvent: false});
this.mins++; this.timeintervalFormGroup.get('customInterval.mins').patchValue(customInterval.mins + 1, {emitEvent: true});
this.onMinsChange();
} }
this.updateView();
} }
private onMinsChange() { private onMinsChange(mins: number) {
if (typeof this.mins === 'undefined') { const customInterval = this.timeintervalFormGroup.get('customInterval').value;
if (typeof mins === 'undefined') {
return; return;
} }
if (this.mins < 0) { if (mins < 0) {
if ((this.days + this.hours) > 0) { if ((customInterval.days + customInterval.hours) > 0) {
this.mins = this.mins + 60; this.timeintervalFormGroup.get('customInterval.mins').patchValue(mins + 60, {emitEvent: false});
this.hours--; this.timeintervalFormGroup.get('customInterval.hours').patchValue(customInterval.hours - 1, {emitEvent: true});
this.onHoursChange();
} else { } else {
this.mins = 0; this.timeintervalFormGroup.get('customInterval.mins').patchValue(0, {emitEvent: false});
} }
} else if (this.mins >= 60) { } else if (mins >= 60) {
this.mins = this.mins - 60; this.timeintervalFormGroup.get('customInterval.mins').patchValue(mins - 60, {emitEvent: false});
this.hours++; this.timeintervalFormGroup.get('customInterval.hours').patchValue(customInterval.hours + 1, {emitEvent: true});
this.onHoursChange();
} }
this.updateView();
} }
private onHoursChange() { private onHoursChange(hours: number) {
if (typeof this.hours === 'undefined') { const customInterval = this.timeintervalFormGroup.get('customInterval').value;
if (typeof hours === 'undefined') {
return; return;
} }
if (this.hours < 0) { if (hours < 0) {
if (this.days > 0) { if (customInterval.days > 0) {
this.hours = this.hours + 24; this.timeintervalFormGroup.get('customInterval.hours').patchValue(hours + 24, {emitEvent: false});
this.days--; this.timeintervalFormGroup.get('customInterval.days').patchValue(customInterval.days - 1, {emitEvent: true});
this.onDaysChange();
} else { } else {
this.hours = 0; this.timeintervalFormGroup.get('customInterval.hours').patchValue(0, {emitEvent: false});
} }
} else if (this.hours >= 24) { } else if (hours >= 24) {
this.hours = this.hours - 24; this.timeintervalFormGroup.get('customInterval.hours').patchValue(hours - 24, {emitEvent: false});
this.days++; this.timeintervalFormGroup.get('customInterval.days').patchValue(customInterval.days + 1, {emitEvent: true});
this.onDaysChange();
} }
this.updateView();
} }
private onDaysChange() { private onDaysChange(days: number) {
if (typeof this.days === 'undefined') { if (typeof days === 'undefined') {
return; return;
} }
if (this.days < 0) { if (days < 0) {
this.days = 0; this.timeintervalFormGroup.get('customInterval.days').patchValue(0, {emitEvent: false});
} }
this.updateView(); }
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
} }
} }

2
ui-ngx/src/app/shared/components/time/timewindow-panel.component.html

@ -159,7 +159,7 @@
</section> </section>
</ng-container> </ng-container>
<section class="tb-form-panel stroked" *ngIf="(isEdit || !timewindow.hideAggInterval) <section class="tb-form-panel stroked" [fxShow]="(isEdit || !timewindow.hideAggInterval)
&& timewindowForm.get('aggregation.type').value !== aggregationTypes.NONE"> && timewindowForm.get('aggregation.type').value !== aggregationTypes.NONE">
<div class="tb-form-panel-title">{{ 'aggregation.group-interval' | translate }}</div> <div class="tb-form-panel-title">{{ 'aggregation.group-interval' | translate }}</div>
<ng-container formGroupName="realtime" *ngIf="timewindow.selectedTab === timewindowTypes.REALTIME"> <ng-container formGroupName="realtime" *ngIf="timewindow.selectedTab === timewindowTypes.REALTIME">

Loading…
Cancel
Save