Timewindow: ability to restrict aggregation options list added

This commit is contained in:
Chantsova Ekaterina 2024-10-21 18:51:14 +03:00
parent 0a8849bf45
commit e406e9d95e
12 changed files with 123 additions and 37 deletions

View File

@ -15,10 +15,33 @@
limitations under the License.
-->
<div [formGroup]="aggregationOptionsConfigForm">
<mat-selection-list formControlName="allowedAggregationTypes">
<mat-list-option *ngFor="let aggregation of aggregations" [value]="aggregation">
{{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}
</mat-list-option>
</mat-selection-list>
</div>
<form [formGroup]="aggregationOptionsConfigForm" class="tb-aggregation-options-form tb-form-panel no-border">
<div class="tb-form-panel-title">{{ 'timewindow.edit-aggregation-functions-list' | translate }}</div>
<div class="tb-form-hint tb-primary-fill">{{ 'timewindow.edit-aggregation-functions-list-hint' | translate }}</div>
<div class="tb-form-table no-gap no-padding">
<div class="tb-form-table-header">
<div class="tb-form-table-header-cell">{{"timewindow.allowed-aggregation-functions" | translate }}</div>
</div>
<div class="tb-form-table-body">
<mat-selection-list formControlName="allowedAggregationTypes">
<mat-list-option *ngFor="let type of allAggregationTypes" [value]="type" togglePosition="before">
{{ aggregationTypesTranslations.get(aggregationTypes[type]) | translate }}
</mat-list-option>
</mat-selection-list>
</div>
</div>
<div class="tb-flex flex-end no-gap">
<button type="button"
mat-button
(click)="cancel()">
{{ 'action.cancel' | translate }}
</button>
<button type="button"
mat-raised-button
color="primary"
(click)="update()"
[disabled]="aggregationOptionsConfigForm.invalid || !aggregationOptionsConfigForm.dirty">
{{ 'action.apply' | translate }}
</button>
</div>
</form>

View File

@ -13,5 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.tb-aggregation-options-form {
height: 100%;
max-width: 350px;
.tb-form-table {
overflow: hidden;
}
.tb-form-table-body {
overflow-y: auto;
}
.tb-form-hint {
flex-shrink: 0;
}
.mdc-list {
display: flex;
flex-direction: column;
gap: 8px;
.mat-mdc-list-item.mdc-list-item--with-leading-checkbox.mdc-list-item--with-one-line {
height: 40px;
}
}
}
}

View File

@ -19,10 +19,6 @@ import { aggregationTranslations, AggregationType } from '@shared/models/time/ti
import { FormBuilder, FormGroup } from '@angular/forms';
import { TbPopoverComponent } from '@shared/components/popover.component';
export interface AggregationOptionsSelectionResult {
allowedAggregationTypes: AggregationType[] | null;
}
@Component({
selector: 'tb-aggregation-options-config-panel',
templateUrl: './aggregation-options-config-panel.component.html',
@ -34,7 +30,7 @@ export class AggregationOptionsConfigPanelComponent implements OnInit {
allowedAggregationTypes: Array<AggregationType>;
@Input()
onClose: (result: AggregationOptionsSelectionResult | null) => void;
onClose: (result: Array<AggregationType> | null) => void;
@Input()
popoverComponent: TbPopoverComponent;
@ -43,7 +39,7 @@ export class AggregationOptionsConfigPanelComponent implements OnInit {
aggregationTypes = AggregationType;
aggregations = Object.keys(AggregationType);
allAggregationTypes: Array<AggregationType> = Object.values(AggregationType);
aggregationTypesTranslations = aggregationTranslations;
@ -57,9 +53,9 @@ export class AggregationOptionsConfigPanelComponent implements OnInit {
update() {
if (this.onClose) {
this.onClose({
allowedAggregationTypes: this.aggregationOptionsConfigForm.get('allowedAggregationTypes').value
});
const allowedAggregationTypes = this.aggregationOptionsConfigForm.get('allowedAggregationTypes').value;
// if full list selected returns empty for optimization
this.onClose(allowedAggregationTypes?.length < this.allAggregationTypes.length ? allowedAggregationTypes : []);
}
}

View File

@ -15,7 +15,9 @@
limitations under the License.
-->
<mat-form-field [formGroup]="aggregationTypeFormGroup" [subscriptSizing]="subscriptSizing" [appearance]="appearance">
<mat-form-field [formGroup]="aggregationTypeFormGroup"
[subscriptSizing]="subscriptSizing" [appearance]="appearance"
class="mat-block">
<mat-label *ngIf="displayLabel">{{ label }}</mat-label>
<mat-select [required]="required" formControlName="aggregationType">
<mat-option *ngFor="let type of aggregationTypes" [value]="type">

View File

@ -112,7 +112,7 @@ export class AggregationTypeSelectComponent implements ControlValueAccessor, OnI
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});
this.aggregationTypeFormGroup.get('aggregationType').patchValue(this.aggregationTypes[0], {emitEvent: true});
}
}
}

View File

@ -16,7 +16,7 @@
@import '../../../../scss/constants';
:host {
min-width: 355px;
min-width: 300px;
display: block;
@media #{$mat-xs} {

View File

@ -51,7 +51,7 @@
{{ 'timewindow.disable-custom-interval' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<div class="tb-form-row column-xs">
<mat-slide-toggle *ngIf="!quickIntervalOnly"
class="mat-slide" formControlName="hideLastInterval">
<div tb-hint-tooltip-icon="{{'timewindow.hide-last-interval' | translate}}">
@ -70,7 +70,7 @@
</ng-container>
<div *ngIf="timewindowForm.get('realtime.realtimeType').value === realtimeTypes.INTERVAL"
class="tb-form-row">
class="tb-form-row column-xs">
<mat-slide-toggle *ngIf="!quickIntervalOnly"
class="mat-slide" formControlName="hideQuickInterval">
<div tb-hint-tooltip-icon="{{'timewindow.hide-relative-interval' | translate}}">
@ -107,7 +107,7 @@
{{ 'timewindow.disable-custom-interval' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide" formControlName="hideLastInterval">
<div tb-hint-tooltip-icon="{{'timewindow.hide-last-interval' | translate}}">
{{ 'timewindow.hide' | translate }}
@ -124,7 +124,7 @@
</div>
</ng-container>
<div *ngIf="timewindowForm.get('history.historyType').value === historyTypes.FIXED" class="tb-form-row">
<div *ngIf="timewindowForm.get('history.historyType').value === historyTypes.FIXED" class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide" formControlName="hideFixedInterval">
<div tb-hint-tooltip-icon="{{'timewindow.hide-fixed-interval' | translate}}">
{{ 'timewindow.hide' | translate }}
@ -140,7 +140,7 @@
</tb-datetime-period>
</div>
<div *ngIf="timewindowForm.get('history.historyType').value === historyTypes.INTERVAL" class="tb-form-row">
<div *ngIf="timewindowForm.get('history.historyType').value === historyTypes.INTERVAL" class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide" formControlName="hideQuickInterval">
<div tb-hint-tooltip-icon="{{'timewindow.hide-relative-interval' | translate}}">
{{ 'timewindow.hide' | translate }}
@ -168,8 +168,10 @@
</mat-slide-toggle>
<ng-container formGroupName="aggregation">
<tb-aggregation-type-select class="flex" subscriptSizing="dynamic" appearance="outline" displayLabel="false"
formControlName="type">
<button matSuffix mat-icon-button type="button" class="tb-mat-24"
formControlName="type"
[allowedAggregationTypes]="timewindowForm.get('allowedAggTypes').value">
<button *ngIf="!timewindowForm.get('hideAggregation').value"
matSuffix mat-icon-button type="button" class="tb-mat-24"
(click)="openAggregationOptionsConfig($event)">
<mat-icon>edit</mat-icon>
</button>

View File

@ -31,13 +31,12 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { TimeService } from '@core/services/time.service';
import { isDefined, isDefinedAndNotNull, mergeDeep } from '@core/utils';
import { deepClone, isDefined, isDefinedAndNotNull, mergeDeep } from '@core/utils';
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
import { TranslateService } from '@ngx-translate/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { TimezoneSelectionResult } from '@shared/components/time/timezone-panel.component';
import { TbPopoverService } from '@shared/components/popover.service';
import {
AggregationOptionsConfigPanelComponent
@ -198,6 +197,8 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On
limit: [ isDefined(aggregation?.limit) ? this.timewindow.aggregation.limit : null ]
}),
timezone: [ isDefined(this.timewindow.timezone) ? this.timewindow.timezone : null ],
allowedAggTypes: [ isDefinedAndNotNull(this.timewindow.allowedAggTypes)
? this.timewindow.allowedAggTypes : null ],
hideAggregation: [ isDefinedAndNotNull(this.timewindow.hideAggregation)
? this.timewindow.hideAggregation : false ],
hideAggInterval: [ isDefinedAndNotNull(this.timewindow.hideAggInterval)
@ -289,6 +290,13 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On
}
}
});
this.timewindowForm.get('hideAggregation').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value: boolean) => {
if (value) {
this.timewindowForm.get('allowedAggTypes').patchValue([]);
}
});
}
ngOnDestroy() {
@ -344,6 +352,11 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On
update() {
const timewindowFormValue = this.timewindowForm.getRawValue();
this.timewindow = mergeDeep(this.timewindow, timewindowFormValue);
if (timewindowFormValue.allowedAggTypes?.length) {
this.timewindow.allowedAggTypes = timewindowFormValue.allowedAggTypes;
} else {
delete this.timewindow.allowedAggTypes;
}
if (!this.aggregation) {
delete this.timewindow.aggregation;
}
@ -405,18 +418,19 @@ export class TimewindowConfigDialogComponent extends PageComponent implements On
this.popoverService.hidePopover(trigger);
} else {
const aggregationConfigPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, AggregationOptionsConfigPanelComponent, ['bottomRight', 'leftBottom'], true, null,
this.viewContainerRef, AggregationOptionsConfigPanelComponent, ['left', 'leftTop', 'leftBottom'], true, null,
{
allowedAggregationTypes: null,
onClose: (result: TimezoneSelectionResult | null) => {
allowedAggregationTypes: deepClone(this.timewindowForm.get('allowedAggTypes').value),
onClose: (result: Array<AggregationType> | null) => {
aggregationConfigPopover.hide();
if (result) {
console.log(result);
this.timewindowForm.get('allowedAggTypes').patchValue(result);
this.timewindowForm.markAsDirty();
}
}
},
{},
{}, {}, false);
{maxHeight: '90vh', height: '100%'},
{}, {}, true, () => {}, {padding: 0});
aggregationConfigPopover.tbComponentRef.instance.popoverComponent = aggregationConfigPopover;
}
this.cd.detectChanges();

View File

@ -126,7 +126,7 @@
<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>
<tb-aggregation-type-select class="flex" subscriptSizing="dynamic" appearance="outline" displayLabel="false"
formControlName="type">
formControlName="type" [allowedAggregationTypes]="allowedAggTypes">
</tb-aggregation-type-select>
</section>

View File

@ -103,6 +103,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O
historyIntervalSelectionAvailable: boolean;
aggregationOptionsAvailable: boolean;
allowedAggTypes: Array<AggregationType>;
private destroy$ = new Subject<void>();
constructor(@Inject(TIMEWINDOW_PANEL_DATA) public data: TimewindowPanelData,
@ -122,6 +124,8 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O
this.timezone = data.timezone;
this.isEdit = data.isEdit;
this.allowedAggTypes = this.timewindow.allowedAggTypes;
if (!this.historyOnly) {
this.timewindowTypeOptions.unshift({
name: this.translate.instant('timewindow.realtime'),
@ -366,6 +370,9 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O
fixedTimewindow: timewindowFormValue.history.fixedTimewindow,
quickInterval: timewindowFormValue.history.quickInterval,
}};
if (!this.timewindow.allowedAggTypes?.length) {
delete this.timewindow.allowedAggTypes;
}
if (this.aggregation) {
this.timewindow.aggregation = {
type: timewindowFormValue.aggregation.type,
@ -508,6 +515,7 @@ export class TimewindowPanelComponent extends PageComponent implements OnInit, O
.subscribe((res) => {
if (res) {
this.timewindow = res;
this.allowedAggTypes = this.timewindow.allowedAggTypes;
this.updateTimewindowForm();
}
});

View File

@ -139,6 +139,7 @@ export interface Aggregation {
export interface Timewindow {
displayValue?: string;
displayTimezoneAbbr?: string;
allowedAggTypes?: Array<AggregationType>;
hideAggregation?: boolean;
hideAggInterval?: boolean;
hideTimezone?: boolean;
@ -301,6 +302,9 @@ export const initModelFromDefaultTimewindow = (value: Timewindow, quickIntervalO
historyOnly: boolean, timeService: TimeService): Timewindow => {
const model = defaultTimewindow(timeService);
if (value) {
if (value.allowedAggTypes?.length) {
model.allowedAggTypes = value.allowedAggTypes;
}
model.hideAggregation = value.hideAggregation;
model.hideAggInterval = value.hideAggInterval;
model.hideTimezone = value.hideTimezone;
@ -429,7 +433,7 @@ export const toHistoryTimewindow = (timewindow: Timewindow, startTimeMs: number,
aggType = AggregationType.AVG;
limit = timeService.getMaxDatapointsLimit();
}
return {
const historyTimewindow: Timewindow = {
hideAggregation: timewindow.hideAggregation || false,
hideAggInterval: timewindow.hideAggInterval || false,
hideTimezone: timewindow.hideTimezone || false,
@ -451,6 +455,10 @@ export const toHistoryTimewindow = (timewindow: Timewindow, startTimeMs: number,
},
timezone: timewindow.timezone
};
if (timewindow.allowedAggTypes?.length) {
historyTimewindow.allowedAggTypes = timewindow.allowedAggTypes;
}
return historyTimewindow;
};
export const timewindowTypeChanged = (newTimewindow: Timewindow, oldTimewindow: Timewindow): boolean => {
@ -898,6 +906,9 @@ export const createTimewindowForComparison = (subscriptionTimewindow: Subscripti
export const cloneSelectedTimewindow = (timewindow: Timewindow): Timewindow => {
const cloned: Timewindow = {};
if (timewindow.allowedAggTypes?.length) {
cloned.allowedAggTypes = timewindow.allowedAggTypes;
}
cloned.hideAggregation = timewindow.hideAggregation || false;
cloned.hideAggInterval = timewindow.hideAggInterval || false;
cloned.hideTimezone = timewindow.hideTimezone || false;

View File

@ -5216,7 +5216,10 @@
"hide-group-interval": "Hide grouping interval from end-users",
"hide-max-values": "Hide max values from end-users",
"hide-timezone": "Hide time zone from end-users",
"disable-custom-interval": "Disable custom interval selection"
"disable-custom-interval": "Disable custom interval selection",
"edit-aggregation-functions-list": "Edit aggregation functions list",
"edit-aggregation-functions-list-hint": "List of available options can be specified.",
"allowed-aggregation-functions": "Allowed aggregation functions"
},
"tooltip": {
"trigger": "Trigger",