Timewindow: ability to restrict aggregation options list added
This commit is contained in:
parent
0a8849bf45
commit
e406e9d95e
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 : []);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
@import '../../../../scss/constants';
|
||||
|
||||
:host {
|
||||
min-width: 355px;
|
||||
min-width: 300px;
|
||||
display: block;
|
||||
|
||||
@media #{$mat-xs} {
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
});
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user