committed by
GitHub
16 changed files with 936 additions and 97 deletions
@ -0,0 +1,43 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
<form [formGroup]="editDetailsFormGroup"> |
|||
<mat-toolbar color="primary"> |
|||
<h2>{{ title | translate }}</h2> |
|||
<span fxFlex></span> |
|||
<button mat-icon-button |
|||
[matDialogClose]="undefined" |
|||
type="button"> |
|||
<mat-icon class="material-icons">close</mat-icon> |
|||
</button> |
|||
</mat-toolbar> |
|||
<div mat-dialog-content> |
|||
<tb-rate-limits-list formControlName="rateLimits"></tb-rate-limits-list> |
|||
</div> |
|||
<div mat-dialog-actions fxLayoutAlign="end center"> |
|||
<button mat-button color="primary" |
|||
type="button" |
|||
[matDialogClose]="undefined" |
|||
cdkFocusInitial> |
|||
{{ 'action.cancel' | translate }} |
|||
</button> |
|||
<button *ngIf="!data.readonly" mat-raised-button color="primary" (click)="save()" |
|||
[disabled]="editDetailsFormGroup.invalid || !editDetailsFormGroup.dirty"> |
|||
{{ 'action.save' | translate }} |
|||
</button> |
|||
</div> |
|||
</form> |
|||
@ -0,0 +1,59 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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, Inject } from '@angular/core'; |
|||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { FormBuilder, FormGroup } from '@angular/forms'; |
|||
import { Router } from '@angular/router'; |
|||
import { DialogComponent } from '@app/shared/components/dialog.component'; |
|||
|
|||
export interface RateLimitsDetailsDialogData { |
|||
rateLimits: string; |
|||
title: string; |
|||
readonly: boolean; |
|||
} |
|||
|
|||
@Component({ |
|||
templateUrl: './rate-limits-details-dialog.component.html' |
|||
}) |
|||
export class RateLimitsDetailsDialogComponent extends DialogComponent<RateLimitsDetailsDialogComponent> { |
|||
|
|||
editDetailsFormGroup: FormGroup; |
|||
|
|||
rateLimits: string = this.data.rateLimits; |
|||
|
|||
title: string = this.data.title; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
protected router: Router, |
|||
@Inject(MAT_DIALOG_DATA) public data: RateLimitsDetailsDialogData, |
|||
public dialogRef: MatDialogRef<RateLimitsDetailsDialogComponent>, |
|||
private fb: FormBuilder) { |
|||
super(store, router, dialogRef); |
|||
this.editDetailsFormGroup = this.fb.group({ |
|||
rateLimits: [this.rateLimits, []] |
|||
}); |
|||
if (this.data.readonly) { |
|||
this.editDetailsFormGroup.disable(); |
|||
} |
|||
} |
|||
|
|||
save(): void { |
|||
this.dialogRef.close(this.editDetailsFormGroup.get('rateLimits').value); |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
<section class="tb-rate-limits-form" [formGroup]="rateLimitsListFormGroup"> |
|||
<div fxFlex [formGroup]="rateLimit" *ngFor="let rateLimit of rateLimitsFormArray.controls; let $index = index"> |
|||
<div class="tb-rate-limits-operation" *ngIf="$index > 0 && rateLimitsFormArray.controls.length > 1" translate> |
|||
tenant-profile.rate-limits.but-less-than |
|||
</div> |
|||
<div fxFlex fxLayout="row" fxLayoutGap="8px"> |
|||
<mat-form-field fxFlex hideRequiredMarker appearance="fill" class="mat-block"> |
|||
<mat-label translate>tenant-profile.rate-limits.number-of-messages</mat-label> |
|||
<input matInput placeholder="{{ 'tenant-profile.rate-limits.number-of-messages' | translate }}" |
|||
type="number" min="1" step="1" formControlName="value" required> |
|||
<mat-error *ngIf="rateLimit.get('value').hasError('required')"> |
|||
{{ 'tenant-profile.rate-limits.number-of-messages-required' | translate }} |
|||
</mat-error> |
|||
<mat-error *ngIf="rateLimit.get('value').hasError('min')"> |
|||
{{ 'tenant-profile.rate-limits.number-of-messages-min' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<mat-form-field fxFlex hideRequiredMarker appearance="fill" class="mat-block"> |
|||
<mat-label translate>tenant-profile.rate-limits.per-seconds</mat-label> |
|||
<input matInput placeholder="{{ 'tenant-profile.rate-limits.per-seconds' | translate }}" |
|||
type="number" min="1" step="1" formControlName="time" required> |
|||
<mat-error *ngIf="rateLimit.get('time').hasError('required')"> |
|||
{{ 'tenant-profile.rate-limits.per-seconds-required' | translate }} |
|||
</mat-error> |
|||
<mat-error *ngIf="rateLimit.get('time').hasError('min')"> |
|||
{{ 'tenant-profile.rate-limits.per-seconds-min' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<button mat-icon-button type="button" color="primary" |
|||
class="tb-rate-limits-button" |
|||
*ngIf="!rateLimitsFormArray.disabled" |
|||
(click)="removeRateLimits($index)" |
|||
[disabled]="disabled" |
|||
[matTooltip]="'tenant-profile.rate-limits.remove-limit' | translate" matTooltipPosition="above"> |
|||
<mat-icon>remove_circle_outline</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<button mat-raised-button color="primary" *ngIf="!rateLimitsFormArray.disabled" |
|||
(click)="addRateLimits()" |
|||
[disabled]="disabled" |
|||
[matTooltip]="'tenant-profile.rate-limits.add-limit' | translate" matTooltipPosition="above"> |
|||
<span translate>tenant-profile.rate-limits.add-limit</span> |
|||
</button> |
|||
<div fxFlex fxLayoutGap="8px" fxLayout="column" class="tb-rate-limits-preview" [ngClass]="{'tb-rate-limits-preview-short': !disabled}"> |
|||
<span translate>tenant-profile.rate-limits.preview</span> |
|||
<tb-rate-limits-text [rateLimitsArray]="rateLimitsArray" [disabled]="disabled"></tb-rate-limits-text> |
|||
</div> |
|||
</section> |
|||
@ -0,0 +1,57 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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 { |
|||
.tb-rate-limits-form { |
|||
@media #{$mat-gt-sm} { |
|||
min-width: 600px; |
|||
} |
|||
} |
|||
|
|||
.tb-rate-limits-preview { |
|||
margin-top: 1.5em; |
|||
span { |
|||
padding-left: 1em; |
|||
} |
|||
tb-rate-limits-text { |
|||
border: 1px groove rgba(0, 0, 0, .25); |
|||
border-radius: 4px; |
|||
padding: 1em; |
|||
} |
|||
} |
|||
|
|||
.tb-rate-limits-operation { |
|||
font-size: 12px; |
|||
color: rgba(0,0,0,.54); |
|||
margin-bottom: 16px; |
|||
} |
|||
|
|||
.tb-rate-limits-button { |
|||
margin-top: 0.5em; |
|||
} |
|||
} |
|||
|
|||
:host ::ng-deep { |
|||
mat-form-field { |
|||
.mat-form-field-wrapper { |
|||
padding-bottom: 1em; |
|||
} |
|||
.mat-form-field-infix { |
|||
width: 100%; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,152 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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, OnDestroy, OnInit } from '@angular/core'; |
|||
import { |
|||
ControlValueAccessor, |
|||
FormArray, |
|||
FormBuilder, |
|||
FormGroup, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
ValidationErrors, |
|||
Validator, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { Subject, Subscription } from 'rxjs'; |
|||
import { RateLimits, rateLimitsArrayToString, stringToRateLimitsArray } from './rate-limits.models'; |
|||
import { isDefinedAndNotNull } from '@core/utils'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-rate-limits-list', |
|||
templateUrl: './rate-limits-list.component.html', |
|||
styleUrls: ['./rate-limits-list.component.scss'], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => RateLimitsListComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => RateLimitsListComponent), |
|||
multi: true |
|||
} |
|||
] |
|||
}) |
|||
export class RateLimitsListComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy { |
|||
|
|||
@Input() disabled: boolean; |
|||
|
|||
rateLimitsListFormGroup: FormGroup; |
|||
|
|||
rateLimitsArray: Array<RateLimits>; |
|||
|
|||
private valueChangeSubscription: Subscription = null; |
|||
private destroy$ = new Subject(); |
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private fb: FormBuilder) {} |
|||
|
|||
ngOnInit(): void { |
|||
this.rateLimitsListFormGroup = this.fb.group({ |
|||
rateLimits: this.fb.array([]) |
|||
}); |
|||
this.valueChangeSubscription = this.rateLimitsListFormGroup.valueChanges |
|||
.pipe(takeUntil(this.destroy$)) |
|||
.subscribe((value) => { |
|||
this.updateView(value?.rateLimits); |
|||
} |
|||
); |
|||
} |
|||
|
|||
public removeRateLimits(index: number) { |
|||
(this.rateLimitsListFormGroup.get('rateLimits') as FormArray).removeAt(index); |
|||
} |
|||
|
|||
public addRateLimits() { |
|||
this.rateLimitsFormArray.push(this.fb.group({ |
|||
value: [null, [Validators.required]], |
|||
time: [null, [Validators.required]] |
|||
})); |
|||
} |
|||
|
|||
get rateLimitsFormArray(): FormArray { |
|||
return this.rateLimitsListFormGroup.get('rateLimits') as FormArray; |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
setDisabledState?(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.rateLimitsListFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.rateLimitsListFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
validate(): ValidationErrors | null { |
|||
return this.rateLimitsListFormGroup.valid ? null : { |
|||
rateLimitsList: {valid: false} |
|||
}; |
|||
} |
|||
|
|||
writeValue(rateLimits: string) { |
|||
const rateLimitsControls: Array<FormGroup> = []; |
|||
if (rateLimits) { |
|||
const rateLimitsArray = rateLimits.split(','); |
|||
for (let i = 0; i < rateLimitsArray.length; i++) { |
|||
const [value, time] = rateLimitsArray[i].split(':'); |
|||
const rateLimitsControl = this.fb.group({ |
|||
value: [value, [Validators.required]], |
|||
time: [time, [Validators.required]] |
|||
}); |
|||
if (this.disabled) { |
|||
rateLimitsControl.disable(); |
|||
} |
|||
rateLimitsControls.push(rateLimitsControl); |
|||
} |
|||
} |
|||
this.rateLimitsListFormGroup.setControl('rateLimits', this.fb.array(rateLimitsControls), {emitEvent: false}); |
|||
this.rateLimitsArray = stringToRateLimitsArray(rateLimits); |
|||
} |
|||
|
|||
updateView(rateLimitsArray: Array<RateLimits>) { |
|||
if (rateLimitsArray.length > 0) { |
|||
const notNullRateLimits = rateLimitsArray.filter(rateLimits => |
|||
isDefinedAndNotNull(rateLimits.value) && isDefinedAndNotNull(rateLimits.time) |
|||
); |
|||
const rateLimitsString = rateLimitsArrayToString(notNullRateLimits); |
|||
this.propagateChange(rateLimitsString); |
|||
this.rateLimitsArray = stringToRateLimitsArray(rateLimitsString); |
|||
} else { |
|||
this.propagateChange(null); |
|||
this.rateLimitsArray = null; |
|||
} |
|||
} |
|||
|
|||
ngOnDestroy() { |
|||
this.destroy$.next(); |
|||
this.destroy$.complete(); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
<div class="tb-rate-limits-text" [ngClass]="{disabled: disabled}" [innerHTML]="rateLimitsText"></div> |
|||
@ -0,0 +1,41 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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. |
|||
*/ |
|||
:host { |
|||
.tb-rate-limits-text { |
|||
overflow: hidden; |
|||
|
|||
&.disabled { |
|||
opacity: 0.7; |
|||
} |
|||
} |
|||
} |
|||
|
|||
:host ::ng-deep { |
|||
.tb-rate-limits-text { |
|||
span { |
|||
font-size: 14px; |
|||
line-height: 1.8em; |
|||
} |
|||
.tb-rate-limits-value { |
|||
font-weight: bold; |
|||
border: 1px groove rgba(0, 0, 0, .25); |
|||
border-radius: 4px; |
|||
padding-left: 4px; |
|||
padding-right: 4px; |
|||
color: #305680; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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, Input, OnChanges, SimpleChanges } from '@angular/core'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { RateLimits, rateLimitsArrayToHtml } from './rate-limits.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-rate-limits-text', |
|||
templateUrl: './rate-limits-text.component.html', |
|||
styleUrls: ['./rate-limits-text.component.scss'] |
|||
}) |
|||
export class RateLimitsTextComponent implements OnChanges { |
|||
|
|||
@Input() |
|||
rateLimitsArray: Array<RateLimits>; |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
rateLimitsText: string; |
|||
|
|||
constructor(private translate: TranslateService) { |
|||
} |
|||
|
|||
ngOnChanges(changes: SimpleChanges): void { |
|||
for (const propName of Object.keys(changes)) { |
|||
if (propName === 'rateLimitsArray') { |
|||
const change = changes[propName]; |
|||
this.updateView(change.currentValue); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private updateView(value: Array<RateLimits>): void { |
|||
if (value?.length) { |
|||
this.rateLimitsText = rateLimitsArrayToHtml(this.translate, value); |
|||
} else { |
|||
this.rateLimitsText = this.translate.instant('tenant-profile.rate-limits.not-set'); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
<div fxFlex fxLayout="row" fxLayoutGap="8px"> |
|||
<fieldset class="fieldset-element"> |
|||
<legend class="legend-element">{{ label | translate }}</legend> |
|||
<div [formGroup]="rateLimitsFormGroup" fxFlex fxLayout="row" fxLayoutGap="8px" |
|||
(click)="onClick($event)" |
|||
[matTooltip]="'tenant-profile.rate-limits.edit-limit' | translate" matTooltipPosition="above"> |
|||
<tb-rate-limits-text [rateLimitsArray]="rateLimitsArray" [disabled]="disabled"></tb-rate-limits-text> |
|||
</div> |
|||
</fieldset> |
|||
<button mat-icon-button color="primary" type="button" *ngIf="!disabled" |
|||
class="tb-rate-limits-button" |
|||
(click)="onClick($event)" |
|||
[matTooltip]="'tenant-profile.rate-limits.add-limit' | translate" matTooltipPosition="above"> |
|||
<mat-icon>add_circle_outline</mat-icon> |
|||
</button> |
|||
</div> |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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. |
|||
*/ |
|||
:host { |
|||
padding: 12px 0 12px 0; |
|||
|
|||
.fieldset-element { |
|||
cursor: pointer; |
|||
padding: 0.5em; |
|||
border: 1px groove rgba(0, 0, 0, 0.25); |
|||
border-radius: 4px; |
|||
width: 100%; |
|||
|
|||
.legend-element { |
|||
color: rgba(0, 0, 0, 0.54); |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
|
|||
.tb-rate-limits-button { |
|||
margin-top: 0.5em; |
|||
} |
|||
} |
|||
@ -0,0 +1,149 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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, |
|||
FormControl, |
|||
FormGroup, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
Validator |
|||
} from '@angular/forms'; |
|||
import { MatDialog } from '@angular/material/dialog'; |
|||
import { |
|||
RateLimitsDetailsDialogComponent, |
|||
RateLimitsDetailsDialogData |
|||
} from '@home/components/profile/tenant/rate-limits/rate-limits-details-dialog.component'; |
|||
import { |
|||
RateLimits, |
|||
rateLimitsDialogTitleTranslationMap, |
|||
rateLimitsLabelTranslationMap, |
|||
RateLimitsType, |
|||
stringToRateLimitsArray |
|||
} from './rate-limits.models'; |
|||
import { isDefined } from '@core/utils'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-rate-limits', |
|||
templateUrl: './rate-limits.component.html', |
|||
styleUrls: ['./rate-limits.component.scss'], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => RateLimitsComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => RateLimitsComponent), |
|||
multi: true, |
|||
} |
|||
] |
|||
}) |
|||
export class RateLimitsComponent implements ControlValueAccessor, OnInit, Validator { |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
@Input() |
|||
type: RateLimitsType; |
|||
|
|||
label: string; |
|||
|
|||
rateLimitsFormGroup: FormGroup; |
|||
|
|||
get rateLimitsArray(): Array<RateLimits> { |
|||
return this.rateLimitsFormGroup.get('rateLimits').value; |
|||
} |
|||
|
|||
private modelValue: string; |
|||
|
|||
private propagateChange = null; |
|||
|
|||
constructor(private dialog: MatDialog, |
|||
private fb: FormBuilder) { |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.label = rateLimitsLabelTranslationMap.get(this.type); |
|||
this.rateLimitsFormGroup = this.fb.group({ |
|||
rateLimits: [null, []] |
|||
}); |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean) { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.rateLimitsFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.rateLimitsFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: string) { |
|||
this.modelValue = value; |
|||
this.updateRateLimitsInfo(); |
|||
} |
|||
|
|||
public validate(c: FormControl) { |
|||
return null; |
|||
} |
|||
|
|||
public onClick($event: Event) { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
const title = rateLimitsDialogTitleTranslationMap.get(this.type); |
|||
this.dialog.open<RateLimitsDetailsDialogComponent, RateLimitsDetailsDialogData, |
|||
string>(RateLimitsDetailsDialogComponent, { |
|||
disableClose: true, |
|||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], |
|||
data: { |
|||
rateLimits: this.modelValue, |
|||
title, |
|||
readonly: this.disabled |
|||
} |
|||
}).afterClosed().subscribe((result) => { |
|||
if (isDefined(result)) { |
|||
this.modelValue = result; |
|||
this.updateModel(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private updateRateLimitsInfo() { |
|||
this.rateLimitsFormGroup.patchValue( |
|||
{ |
|||
rateLimits: stringToRateLimitsArray(this.modelValue) |
|||
} |
|||
); |
|||
} |
|||
|
|||
private updateModel() { |
|||
this.updateRateLimitsInfo(); |
|||
this.propagateChange(this.modelValue); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,125 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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 { TranslateService } from '@ngx-translate/core'; |
|||
|
|||
export interface RateLimits { |
|||
value: string; |
|||
time: string; |
|||
} |
|||
|
|||
export enum RateLimitsType { |
|||
DEVICE_MESSAGES = 'DEVICE_MESSAGES', |
|||
DEVICE_TELEMETRY_MESSAGES = 'DEVICE_TELEMETRY_MESSAGES', |
|||
DEVICE_TELEMETRY_DATA_POINTS = 'DEVICE_TELEMETRY_DATA_POINTS', |
|||
TENANT_MESSAGES = 'TENANT_MESSAGES', |
|||
TENANT_TELEMETRY_MESSAGES = 'TENANT_TELEMETRY_MESSAGES', |
|||
TENANT_TELEMETRY_DATA_POINTS = 'TENANT_TELEMETRY_DATA_POINTS', |
|||
TENANT_SERVER_REST_LIMITS_CONFIGURATION = 'TENANT_SERVER_REST_LIMITS_CONFIGURATION', |
|||
CUSTOMER_SERVER_REST_LIMITS_CONFIGURATION = 'CUSTOMER_SERVER_REST_LIMITS_CONFIGURATION', |
|||
WS_UPDATE_PER_SESSION_RATE_LIMIT = 'WS_UPDATE_PER_SESSION_RATE_LIMIT', |
|||
CASSANDRA_QUERY_TENANT_RATE_LIMITS_CONFIGURATION = 'CASSANDRA_QUERY_TENANT_RATE_LIMITS_CONFIGURATION', |
|||
TENANT_ENTITY_EXPORT_RATE_LIMIT = 'TENANT_ENTITY_EXPORT_RATE_LIMIT', |
|||
TENANT_ENTITY_IMPORT_RATE_LIMIT = 'TENANT_ENTITY_IMPORT_RATE_LIMIT' |
|||
} |
|||
|
|||
export const rateLimitsLabelTranslationMap = new Map<RateLimitsType, string>( |
|||
[ |
|||
[RateLimitsType.TENANT_MESSAGES, 'tenant-profile.rate-limits.transport-tenant-msg'], |
|||
[RateLimitsType.TENANT_TELEMETRY_MESSAGES, 'tenant-profile.rate-limits.transport-tenant-telemetry-msg'], |
|||
[RateLimitsType.TENANT_TELEMETRY_DATA_POINTS, 'tenant-profile.rate-limits.transport-tenant-telemetry-data-points'], |
|||
[RateLimitsType.DEVICE_MESSAGES, 'tenant-profile.rate-limits.transport-device-msg'], |
|||
[RateLimitsType.DEVICE_TELEMETRY_MESSAGES, 'tenant-profile.rate-limits.transport-device-telemetry-msg'], |
|||
[RateLimitsType.DEVICE_TELEMETRY_DATA_POINTS, 'tenant-profile.rate-limits.transport-device-telemetry-data-points'], |
|||
[RateLimitsType.TENANT_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.transport-tenant-msg-rate-limit'], |
|||
[RateLimitsType.CUSTOMER_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.customer-rest-limits'], |
|||
[RateLimitsType.WS_UPDATE_PER_SESSION_RATE_LIMIT, 'tenant-profile.ws-limit-updates-per-session'], |
|||
[RateLimitsType.CASSANDRA_QUERY_TENANT_RATE_LIMITS_CONFIGURATION, 'tenant-profile.cassandra-tenant-limits-configuration'], |
|||
[RateLimitsType.TENANT_ENTITY_EXPORT_RATE_LIMIT, 'tenant-profile.tenant-entity-export-rate-limit'], |
|||
[RateLimitsType.TENANT_ENTITY_IMPORT_RATE_LIMIT, 'tenant-profile.tenant-entity-import-rate-limit'], |
|||
] |
|||
); |
|||
|
|||
export const rateLimitsDialogTitleTranslationMap = new Map<RateLimitsType, string>( |
|||
[ |
|||
[RateLimitsType.TENANT_MESSAGES, 'tenant-profile.rate-limits.edit-transport-tenant-msg-title'], |
|||
[RateLimitsType.TENANT_TELEMETRY_MESSAGES, 'tenant-profile.rate-limits.edit-transport-tenant-telemetry-msg-title'], |
|||
[RateLimitsType.TENANT_TELEMETRY_DATA_POINTS, 'tenant-profile.rate-limits.edit-transport-tenant-telemetry-data-points-title'], |
|||
[RateLimitsType.DEVICE_MESSAGES, 'tenant-profile.rate-limits.edit-transport-device-msg-title'], |
|||
[RateLimitsType.DEVICE_TELEMETRY_MESSAGES, 'tenant-profile.rate-limits.edit-transport-device-telemetry-msg-title'], |
|||
[RateLimitsType.DEVICE_TELEMETRY_DATA_POINTS, 'tenant-profile.rate-limits.edit-transport-device-telemetry-data-points-title'], |
|||
[RateLimitsType.TENANT_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.rate-limits.edit-transport-tenant-msg-rate-limit-title'], |
|||
[RateLimitsType.CUSTOMER_SERVER_REST_LIMITS_CONFIGURATION, 'tenant-profile.rate-limits.edit-customer-rest-limits-title'], |
|||
[RateLimitsType.WS_UPDATE_PER_SESSION_RATE_LIMIT, 'tenant-profile.rate-limits.edit-ws-limit-updates-per-session-title'], |
|||
[RateLimitsType.CASSANDRA_QUERY_TENANT_RATE_LIMITS_CONFIGURATION, 'tenant-profile.rate-limits.edit-cassandra-tenant-limits-configuration-title'], |
|||
[RateLimitsType.TENANT_ENTITY_EXPORT_RATE_LIMIT, 'tenant-profile.rate-limits.edit-tenant-entity-export-rate-limit-title'], |
|||
[RateLimitsType.TENANT_ENTITY_IMPORT_RATE_LIMIT, 'tenant-profile.rate-limits.edit-tenant-entity-import-rate-limit-title'], |
|||
] |
|||
); |
|||
|
|||
export function stringToRateLimitsArray(rateLimits: string): Array<RateLimits> { |
|||
const result: Array<RateLimits> = []; |
|||
if (rateLimits?.length > 0) { |
|||
const rateLimitsArrays = rateLimits.split(','); |
|||
for (let i = 0; i < rateLimitsArrays.length; i++) { |
|||
const [value, time] = rateLimitsArrays[i].split(':'); |
|||
const rateLimitControl = { |
|||
value, |
|||
time |
|||
}; |
|||
result.push(rateLimitControl); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
export function rateLimitsArrayToString(rateLimits: Array<RateLimits>): string { |
|||
let result = ''; |
|||
for (let i = 0; i < rateLimits.length; i++) { |
|||
result = result.concat(rateLimits[i].value, ':', rateLimits[i].time); |
|||
if ((rateLimits.length > 1) && (i !== rateLimits.length - 1)) { |
|||
result = result.concat(','); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
export function rateLimitsArrayToHtml(translate: TranslateService, rateLimitsArray: Array<RateLimits>): string { |
|||
const rateLimitsHtml = rateLimitsArray.map((rateLimits, index) => { |
|||
const isLast: boolean = index === rateLimitsArray.length - 1; |
|||
return rateLimitsToHtml(translate, rateLimits, isLast); |
|||
}); |
|||
let result: string; |
|||
if (rateLimitsHtml.length > 1) { |
|||
const butLessThanText = translate.instant('tenant-profile.rate-limits.but-less-than'); |
|||
result = rateLimitsHtml.join(' <span class="disabled">' + butLessThanText + '</span> '); |
|||
} else { |
|||
result = rateLimitsHtml[0]; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
function rateLimitsToHtml(translate: TranslateService, rateLimit: RateLimits, isLast: boolean): string { |
|||
const value = rateLimit.value; |
|||
const time = rateLimit.time; |
|||
const operation = translate.instant('tenant-profile.rate-limits.messages-per'); |
|||
const seconds = translate.instant('tenant-profile.rate-limits.sec'); |
|||
const comma = isLast ? '' : ','; |
|||
return `<span class="tb-rate-limits-value">${value}</span>
|
|||
<span>${operation}</span> |
|||
<span class="tb-rate-limits-value"> ${time}</span> |
|||
<span>${seconds}${comma}</span><br>`;
|
|||
} |
|||
Loading…
Reference in new issue