UI: timewindow panel realtime mode redesign

This commit is contained in:
Chantsova Ekaterina 2024-06-14 19:01:39 +03:00
parent 83cc70e3af
commit 9b7c8595ee
10 changed files with 141 additions and 124 deletions

View File

@ -16,7 +16,7 @@
-->
<section class="interval-section" fxLayout="row" fxFlex>
<mat-form-field fxFlex>
<mat-form-field fxFlex [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timewindow.interval</mat-label>
<mat-select [disabled]="disabled" [(ngModel)]="modelValue" (ngModelChange)="onIntervalChange()">
<mat-option *ngFor="let interval of intervals" [value]="interval">

View File

@ -17,6 +17,7 @@
import { Component, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { QuickTimeInterval, QuickTimeIntervalTranslationMap } from '@shared/models/time/time.models';
import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field';
@Component({
selector: 'tb-quick-time-interval',
@ -43,6 +44,12 @@ export class QuickTimeIntervalComponent implements OnInit, ControlValueAccessor
@Input() onlyCurrentInterval = false;
@Input()
subscriptSizing: SubscriptSizing = 'fixed';
@Input()
appearance: MatFormFieldAppearance = 'fill';
private propagateChange = (_: any) => {};
constructor() {

View File

@ -22,26 +22,26 @@
</section>
<section class="interval-section" fxLayout="column" fxFlex [fxShow]="advanced && (isEdit || !hideFlag)">
<section fxLayout="row wrap" fxLayoutAlign="start start" fxFlex fxLayoutGap="6px">
<mat-form-field class="number-input">
<mat-form-field class="number-input" [appearance]="appearance">
<mat-label translate>timeinterval.days</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" min="0" [(ngModel)]="days" (ngModelChange)="onTimeInputChange('days')"/>
</mat-form-field>
<mat-form-field class="number-input">
<mat-form-field class="number-input" [appearance]="appearance">
<mat-label translate>timeinterval.hours</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" [(ngModel)]="hours" (ngModelChange)="onTimeInputChange('hours')"/>
</mat-form-field>
<mat-form-field class="number-input">
<mat-form-field class="number-input" [appearance]="appearance">
<mat-label translate>timeinterval.minutes</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" [(ngModel)]="mins" (ngModelChange)="onTimeInputChange('mins')"/>
</mat-form-field>
<mat-form-field class="number-input">
<mat-form-field class="number-input" [appearance]="appearance">
<mat-label translate>timeinterval.seconds</mat-label>
<input matInput [disabled]="hideFlag || disabled" type="number" step="1" [(ngModel)]="secs" (ngModelChange)="onTimeInputChange('secs')"/>
</mat-form-field>
</section>
</section>
<section fxLayout="row" fxFlex [fxShow]="!advanced && (isEdit || !hideFlag)">
<mat-form-field fxFlex [subscriptSizing]="subscriptSizing">
<mat-form-field fxFlex [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label *ngIf="predefinedName" translate>{{ predefinedName }}</mat-label>
<mat-select [disabled]="hideFlag || disabled" [(ngModel)]="interval" (ngModelChange)="onIntervalChange()" style="min-width: 150px;">
<mat-option *ngFor="let interval of intervals" [value]="interval.value">

View File

@ -18,7 +18,7 @@ import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@ang
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { TimeService } from '@core/services/time.service';
import { coerceNumberProperty } from '@angular/cdk/coercion';
import { SubscriptSizing } from '@angular/material/form-field';
import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field';
import { coerceBoolean } from '@shared/decorators/coercion';
import { Interval, IntervalMath, TimeInterval } from '@shared/models/time/time.models';
import { isDefined } from '@core/utils';
@ -85,6 +85,9 @@ export class TimeintervalComponent implements OnInit, ControlValueAccessor {
@Input()
subscriptSizing: SubscriptSizing = 'fixed';
@Input()
appearance: MatFormFieldAppearance = 'fill';
days = 0;
hours = 0;
mins = 1;

View File

@ -19,73 +19,54 @@
<mat-tab-group [ngClass]="{'tb-headless': historyOnly}"
(selectedTabChange)="onTimewindowTypeChange()" [(selectedIndex)]="timewindow.selectedTab">
<mat-tab label="{{ 'timewindow.realtime' | translate }}">
<section fxLayout="row">
<section *ngIf="isEdit" fxLayout="column" fxLayoutAlign="start center"
style="padding-top: 8px; padding-left: 16px;">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideInterval"
(ngModelChange)="onHideIntervalChanged()"></mat-checkbox>
</section>
<section fxLayout="column" fxFlex [fxShow]="isEdit || !timewindow.hideInterval">
<div formGroupName="realtime" class="mat-content mat-padding" style="padding-top: 8px;">
<mat-radio-group *ngIf="!quickIntervalOnly"
[fxShow]="isEdit || (!timewindow.hideLastInterval && !timewindow.hideQuickInterval)"
formControlName="realtimeType">
<mat-radio-button [value]="realtimeTypes.LAST_INTERVAL" color="primary">
<section fxLayout="row">
<section *ngIf="isEdit" fxLayout="column" fxLayoutAlign="start center" style="padding-right: 8px;">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideLastInterval"
(ngModelChange)="onHideLastIntervalChanged()"></mat-checkbox>
</section>
<section fxLayout="column">
<span translate>timewindow.last</span>
<tb-timeinterval
formControlName="timewindowMs"
predefinedName="timewindow.last"
[fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL"
style="padding-top: 8px;"></tb-timeinterval>
</section>
</section>
</mat-radio-button>
<mat-radio-button [value]="realtimeTypes.INTERVAL" color="primary">
<section fxLayout="row">
<section *ngIf="isEdit" fxLayout="column" fxLayoutAlign="start center" style="padding-right: 8px;">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideQuickInterval"
(ngModelChange)="onHideQuickIntervalChanged()"></mat-checkbox>
</section>
<section fxLayout="column">
<span translate>timewindow.interval</span>
<tb-quick-time-interval
formControlName="quickInterval"
onlyCurrentInterval="true"
[fxShow]="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
style="padding-top: 8px"></tb-quick-time-interval>
</section>
</section>
</mat-radio-button>
</mat-radio-group>
<tb-timeinterval *ngIf="!isEdit && !timewindow.hideLastInterval && timewindow.hideQuickInterval"
formControlName="timewindowMs"
predefinedName="timewindow.last"
required
style="padding-top: 8px;"></tb-timeinterval>
<tb-quick-time-interval
*ngIf="quickIntervalOnly || !isEdit && timewindow.hideLastInterval && !timewindow.hideQuickInterval"
formControlName="quickInterval"
onlyCurrentInterval="true"
required
style="padding-top: 8px"></tb-quick-time-interval>
<div class="tb-flex column">
<section class="tb-form-panel stroked" [fxShow]="isEdit || !timewindow.hideInterval">
<div class="tb-form-panel-title">{{ 'timewindow.time-range' | translate }}</div>
<div class="tb-flex align-center space-between">
<ng-container formGroupName="realtime">
<tb-toggle-select *ngIf="!quickIntervalOnly"
[fxShow]="isEdit || (!timewindow.hideLastInterval && !timewindow.hideQuickInterval)"
appearance="fill" [options]="realtimeTimewindowOptions" formControlName="realtimeType"
style="max-width: 100%">
</tb-toggle-select>
</ng-container>
<tb-timezone-select fxFlex [fxShow]="!timewindow.hideTimezone"
localBrowserTimezonePlaceholderOnEmpty="true"
formControlName="timezone"
subscriptSizing="dynamic"
appearance="outline">
</tb-timezone-select>
</div>
</section>
</section>
<ng-container *ngTemplateOutlet="additionalData">
</ng-container>
<ng-container formGroupName="realtime">
<ng-container *ngIf="isEdit || !timewindow.hideLastInterval &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL">
<tb-timeinterval
formControlName="timewindowMs"
subscriptSizing="dynamic"
appearance="outline"
[required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.LAST_INTERVAL">
</tb-timeinterval>
</ng-container>
<ng-container *ngIf="!timewindow.hideQuickInterval &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL">
<tb-quick-time-interval
formControlName="quickInterval"
onlyCurrentInterval="true"
subscriptSizing="dynamic"
appearance="outline"
[required]="timewindow.selectedTab === timewindowTypes.REALTIME &&
timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL">
</tb-quick-time-interval>
</ng-container>
</ng-container>
</section>
<ng-container *ngTemplateOutlet="aggregationConfig">
</ng-container>
</div>
</mat-tab>
<mat-tab label="{{ 'timewindow.history' | translate }}">
<section fxLayout="row">
@ -110,6 +91,8 @@
formControlName="timewindowMs"
predefinedName="timewindow.last"
class="history-time-input"
subscriptSizing="dynamic"
appearance="outline"
[fxShow]="timewindowForm.get('history.historyType').value === historyTypes.LAST_INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
timewindowForm.get('history.historyType').value === historyTypes.LAST_INTERVAL"
@ -134,6 +117,8 @@
<tb-quick-time-interval
formControlName="quickInterval"
class="history-time-input"
subscriptSizing="dynamic"
appearance="outline"
[fxShow]="timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
[required]="timewindow.selectedTab === timewindowTypes.HISTORY &&
timewindowForm.get('history.historyType').value === historyTypes.INTERVAL"
@ -144,54 +129,42 @@
</div>
</section>
</section>
<ng-container *ngTemplateOutlet="additionalData">
<ng-container *ngTemplateOutlet="aggregationConfig">
</ng-container>
</mat-tab>
</mat-tab-group>
<ng-template #additionalData>
<div *ngIf="aggregation" formGroupName="aggregation" class="mat-content mat-padding" fxLayout="column">
<section fxLayout="row">
<section fxLayout="column" fxLayoutAlign="start center" [fxShow]="isEdit">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideAggregation"
(ngModelChange)="onHideAggregationChanged()"></mat-checkbox>
</section>
<section fxFlex fxLayout="column" [fxShow]="isEdit || !timewindow.hideAggregation">
<mat-form-field>
<mat-label translate>aggregation.function</mat-label>
<mat-select formControlName="type" style="min-width: 150px;">
<mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</section>
<ng-template #aggregationConfig>
<div *ngIf="aggregation" formGroupName="aggregation" class="tb-flex column">
<section class="tb-form-panel stroked" [fxShow]="isEdit || !timewindow.hideAggregation">
<div class="tb-form-panel-title">{{ 'aggregation.aggregation' | translate }}</div>
<mat-form-field subscriptSizing="dynamic" appearance="outline">
<mat-select formControlName="type" style="min-width: 150px;">
<mat-option *ngFor="let aggregation of aggregations" [value]="aggregation">
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</section>
<section fxLayout="row" *ngIf="timewindowForm.get('aggregation.type').value === aggregationTypes.NONE">
<section fxLayout="column" fxLayoutAlign="start center" [fxShow]="isEdit">
<label class="tb-small hide-label" translate>timewindow.hide</label>
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideAggInterval"
(ngModelChange)="onHideAggIntervalChanged()"></mat-checkbox>
</section>
<section fxLayout="column" fxFlex [fxShow]="isEdit || !timewindow.hideAggInterval">
<div class="limit-slider-container" fxLayout="row" fxLayoutAlign="start center"
fxLayout.xs="column" fxLayoutAlign.xs="stretch">
<label translate>aggregation.limit</label>
<div fxLayout="row" fxLayoutAlign="start center" fxFlex>
<mat-slider fxFlex
discrete
min="{{minDatapointsLimit()}}"
max="{{maxDatapointsLimit()}}"><input matSliderThumb formControlName="limit"/>
</mat-slider>
<mat-form-field class="limit-slider-value">
<input matInput formControlName="limit" type="number" step="1"
[value]="timewindowForm.get('aggregation.limit').value"
min="{{minDatapointsLimit()}}"
max="{{maxDatapointsLimit()}}"/>
</mat-form-field>
</div>
<section class="tb-form-panel stroked"
*ngIf="timewindowForm.get('aggregation.type').value === aggregationTypes.NONE && (isEdit || !timewindow.hideAggInterval)">
<div class="tb-form-panel-title">{{ 'aggregation.limit' | translate }}</div>
<div class="limit-slider-container" fxLayout="row" fxLayoutAlign="start center"
fxLayout.xs="column" fxLayoutAlign.xs="stretch">
<div fxLayout="row" fxLayoutAlign="start center" fxFlex>
<mat-slider fxFlex
discrete
min="{{minDatapointsLimit()}}"
max="{{maxDatapointsLimit()}}"><input matSliderThumb formControlName="limit"/>
</mat-slider>
<mat-form-field class="limit-slider-value" subscriptSizing="dynamic" appearance="outline">
<input matInput formControlName="limit" type="number" step="1"
[value]="timewindowForm.get('aggregation.limit').value"
min="{{minDatapointsLimit()}}"
max="{{maxDatapointsLimit()}}"/>
</mat-form-field>
</div>
</section>
</div>
</section>
</div>
<div formGroupName="realtime"
@ -204,6 +177,8 @@
(hideFlagChange)="onHideAggIntervalChanged()"
[min]="minRealtimeAggInterval()" [max]="maxRealtimeAggInterval()"
useCalendarIntervals
subscriptSizing="dynamic"
appearance="outline"
predefinedName="aggregation.group-interval">
</tb-timeinterval>
</div>
@ -217,6 +192,8 @@
(hideFlagChange)="onHideAggIntervalChanged()"
[min]="minHistoryAggInterval()" [max]="maxHistoryAggInterval()"
useCalendarIntervals
subscriptSizing="dynamic"
appearance="outline"
predefinedName="aggregation.group-interval">
</tb-timeinterval>
</div>
@ -226,10 +203,11 @@
<mat-checkbox [ngModelOptions]="{standalone: true}" [(ngModel)]="timewindow.hideTimezone"
(ngModelChange)="onHideTimezoneChanged()"></mat-checkbox>
</section>
<tb-timezone-select fxFlex [fxShow]="isEdit || !timewindow.hideTimezone"
localBrowserTimezonePlaceholderOnEmpty="true"
formControlName="timezone">
</tb-timezone-select>
<!-- <tb-timezone-select fxFlex [fxShow]="isEdit || !timewindow.hideTimezone"-->
<!-- localBrowserTimezonePlaceholderOnEmpty="true"-->
<!-- formControlName="timezone"-->
<!-- appearance="outline">-->
<!-- </tb-timezone-select>-->
</div>
</ng-template>
</form>

View File

@ -22,6 +22,10 @@
max-width: 100%;
background-color: #fff;
.tb-flex {
gap: 16px;
}
.mat-content {
overflow: hidden;
}
@ -35,7 +39,7 @@
margin-right: 5px;
}
tb-timeinterval[ng-reflect-fx-show="true"] {
tb-timeinterval[ng-reflect-fxe-show="true"] {
margin-bottom: -16px;
}
@ -78,4 +82,8 @@
.mat-mdc-tab-group:not(.tb-headless) {
height: 100%;
}
.mat-mdc-tab-body-content {
padding: 16px;
}
}

View File

@ -32,6 +32,9 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms
import { TimeService } from '@core/services/time.service';
import { isDefined } from '@core/utils';
import { OverlayRef } from '@angular/cdk/overlay';
import { WidgetConfigMode } from '@shared/models/widget.models';
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
import { TranslateService } from '@ngx-translate/core';
export interface TimewindowPanelData {
historyOnly: boolean;
@ -82,11 +85,23 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
result: Timewindow;
realtimeTimewindowOptions: ToggleHeaderOption[] = [
{
name: this.translate.instant('timewindow.last'),
value: this.realtimeTypes.LAST_INTERVAL
},
{
name: this.translate.instant('timewindow.interval'),
value: this.realtimeTypes.INTERVAL
}
];
constructor(@Inject(TIMEWINDOW_PANEL_DATA) public data: TimewindowPanelData,
public overlayRef: OverlayRef,
protected store: Store<AppState>,
public fb: UntypedFormBuilder,
private timeService: TimeService,
private translate: TranslateService,
public viewContainerRef: ViewContainerRef) {
super(store);
this.historyOnly = data.historyOnly;
@ -380,4 +395,5 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit {
this.timewindowForm.markAsDirty();
}
protected readonly WidgetConfigMode = WidgetConfigMode;
}

View File

@ -15,7 +15,8 @@
limitations under the License.
-->
<mat-form-field [formGroup]="selectTimezoneFormGroup" fxFlex class="mat-block" [appearance]="appearance">
<mat-form-field [formGroup]="selectTimezoneFormGroup" fxFlex class="mat-block"
[subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-label translate>timezone.timezone</mat-label>
<input matInput type="text" placeholder="{{ 'timezone.select-timezone' | translate }}"
#timezoneInput

View File

@ -16,7 +16,7 @@
import { AfterViewInit, Component, forwardRef, Input, NgZone, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatFormFieldAppearance } from '@angular/material/form-field';
import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field';
import { Observable, of } from 'rxjs';
import { map, mergeMap, share, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@ -45,6 +45,9 @@ export class TimezoneSelectComponent implements ControlValueAccessor, OnInit, Af
defaultTimezoneId: string = null;
@Input()
subscriptSizing: SubscriptSizing = 'fixed';
@Input()
appearance: MatFormFieldAppearance = 'fill';

View File

@ -4694,7 +4694,8 @@
"font": "Font",
"color": "Color",
"displayTypePrefix": "Display Realtime/History prefix",
"preview": "Preview"
"preview": "Preview",
"time-range": "Time range"
},
"tooltip": {
"trigger": "Trigger",