Merge pull request #13493 from vvlladd28/improvement/rate-limits/validation-text
Improved rate limits labels and added validation for duplicate time values
This commit is contained in:
commit
b0b682f6a5
@ -17,31 +17,33 @@
|
||||
-->
|
||||
<section class="tb-rate-limits-form" [formGroup]="rateLimitsListFormGroup">
|
||||
<div class="flex-1" [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>
|
||||
@if($index > 0) {
|
||||
<div class="tb-rate-limits-operation" translate>tenant-profile.rate-limits.and-also-less-than</div>
|
||||
}
|
||||
<div class="flex flex-1 flex-row gap-2">
|
||||
<mat-form-field hideRequiredMarker appearance="fill" class="mat-block flex-1">
|
||||
<mat-form-field hideRequiredMarker appearance="fill" class="mat-block flex-1" subscriptSizing="dynamic">
|
||||
<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-hint></mat-hint>
|
||||
@if (rateLimit.get('value').hasError('required')) {
|
||||
<mat-error translate>tenant-profile.rate-limits.number-of-messages-required</mat-error>
|
||||
} @else if(rateLimit.get('value').hasError('min')) {
|
||||
<mat-error translate>tenant-profile.rate-limits.number-of-messages-min</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<mat-form-field hideRequiredMarker appearance="fill" class="mat-block flex-1">
|
||||
<mat-form-field hideRequiredMarker appearance="fill" class="mat-block flex-1" subscriptSizing="dynamic">
|
||||
<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-hint></mat-hint>
|
||||
@if (rateLimit.get('time').hasError('required')) {
|
||||
<mat-error translate>tenant-profile.rate-limits.per-seconds-required</mat-error>
|
||||
} @else if (rateLimit.get('time').hasError('min')) {
|
||||
<mat-error translate>tenant-profile.rate-limits.per-seconds-min</mat-error>
|
||||
} @else if (rateLimit.get('time').hasError('duplicateTime')) {
|
||||
<mat-error translate>tenant-profile.rate-limits.per-seconds-duplicate</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<button mat-icon-button type="button" color="primary"
|
||||
class="tb-rate-limits-button"
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
:host {
|
||||
.tb-rate-limits-form {
|
||||
@media #{$mat-gt-sm} {
|
||||
min-width: 600px;
|
||||
min-width: 620px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,22 +14,23 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
UntypedFormArray,
|
||||
UntypedFormBuilder,
|
||||
UntypedFormGroup,
|
||||
FormArray,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
NG_VALIDATORS,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ValidationErrors,
|
||||
Validator,
|
||||
ValidatorFn,
|
||||
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';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-rate-limits-list',
|
||||
@ -48,51 +49,51 @@ import { takeUntil } from 'rxjs/operators';
|
||||
}
|
||||
]
|
||||
})
|
||||
export class RateLimitsListComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy {
|
||||
export class RateLimitsListComponent implements ControlValueAccessor, Validator, OnInit {
|
||||
|
||||
@Input() disabled: boolean;
|
||||
|
||||
rateLimitsListFormGroup: UntypedFormGroup;
|
||||
rateLimitsListFormGroup: FormGroup;
|
||||
|
||||
rateLimitsArray: Array<RateLimits>;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
private propagateChange = (v: any) => { };
|
||||
private propagateChange = (_v: any) => { };
|
||||
|
||||
constructor(private fb: UntypedFormBuilder) {}
|
||||
constructor(private fb: FormBuilder,
|
||||
private destroyRef: DestroyRef) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.rateLimitsListFormGroup = this.fb.group({
|
||||
rateLimits: this.fb.array([])
|
||||
});
|
||||
this.rateLimitsListFormGroup.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.pipe(takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((value) => {
|
||||
this.updateView(value?.rateLimits);
|
||||
this.updateView(value?.rateLimits ?? []);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public removeRateLimits(index: number) {
|
||||
(this.rateLimitsListFormGroup.get('rateLimits') as UntypedFormArray).removeAt(index);
|
||||
this.rateLimitsFormArray.removeAt(index);
|
||||
}
|
||||
|
||||
public addRateLimits() {
|
||||
this.rateLimitsFormArray.push(this.fb.group({
|
||||
value: [null, [Validators.required]],
|
||||
time: [null, [Validators.required]]
|
||||
time: [null, [Validators.required, this.uniqTimeRequired()]]
|
||||
}));
|
||||
}
|
||||
|
||||
get rateLimitsFormArray(): UntypedFormArray {
|
||||
return this.rateLimitsListFormGroup.get('rateLimits') as UntypedFormArray;
|
||||
get rateLimitsFormArray(): FormArray<FormGroup> {
|
||||
return this.rateLimitsListFormGroup.get('rateLimits') as FormArray<FormGroup>;
|
||||
}
|
||||
|
||||
registerOnChange(fn: any): void {
|
||||
this.propagateChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: any): void {
|
||||
registerOnTouched(_fn: any): void {
|
||||
}
|
||||
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
@ -111,26 +112,26 @@ export class RateLimitsListComponent implements ControlValueAccessor, Validator,
|
||||
}
|
||||
|
||||
writeValue(rateLimits: string) {
|
||||
const rateLimitsControls: Array<UntypedFormGroup> = [];
|
||||
const rateLimitsControls: Array<FormGroup> = [];
|
||||
if (rateLimits) {
|
||||
const rateLimitsArray = rateLimits.split(',');
|
||||
for (let i = 0; i < rateLimitsArray.length; i++) {
|
||||
const [value, time] = rateLimitsArray[i].split(':');
|
||||
this.rateLimitsArray = stringToRateLimitsArray(rateLimits);
|
||||
this.rateLimitsArray.forEach((rateLimit) => {
|
||||
const rateLimitsControl = this.fb.group({
|
||||
value: [value, [Validators.required]],
|
||||
time: [time, [Validators.required]]
|
||||
value: [rateLimit.value, [Validators.required]],
|
||||
time: [rateLimit.time, [Validators.required, this.uniqTimeRequired()]]
|
||||
});
|
||||
if (this.disabled) {
|
||||
rateLimitsControl.disable();
|
||||
}
|
||||
rateLimitsControls.push(rateLimitsControl);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.rateLimitsArray = null;
|
||||
}
|
||||
this.rateLimitsListFormGroup.setControl('rateLimits', this.fb.array(rateLimitsControls), {emitEvent: false});
|
||||
this.rateLimitsArray = stringToRateLimitsArray(rateLimits);
|
||||
}
|
||||
|
||||
updateView(rateLimitsArray: Array<RateLimits>) {
|
||||
private updateView(rateLimitsArray: Array<RateLimits>) {
|
||||
if (rateLimitsArray.length > 0) {
|
||||
const notNullRateLimits = rateLimitsArray.filter(rateLimits =>
|
||||
isDefinedAndNotNull(rateLimits.value) && isDefinedAndNotNull(rateLimits.time)
|
||||
@ -144,8 +145,22 @@ export class RateLimitsListComponent implements ControlValueAccessor, Validator,
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
private uniqTimeRequired(): ValidatorFn {
|
||||
return (control: FormControl) => {
|
||||
const formGroup = control.parent as FormGroup;
|
||||
if (!formGroup) return null;
|
||||
|
||||
const formArray = formGroup.parent as FormArray;
|
||||
if (!formArray) return null;
|
||||
|
||||
const newTime = control.value;
|
||||
const index = formArray.controls.indexOf(formGroup);
|
||||
|
||||
const isDuplicate = formArray.controls
|
||||
.filter((_, i) => i !== index)
|
||||
.some(group => group.get('time')?.value === newTime && newTime !== '');
|
||||
|
||||
return isDuplicate ? { duplicateTime: true } : null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,8 +17,8 @@
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
export interface RateLimits {
|
||||
value: string;
|
||||
time: string;
|
||||
value: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
export enum RateLimitsType {
|
||||
@ -113,11 +113,11 @@ 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(':');
|
||||
for (const limit of rateLimitsArrays) {
|
||||
const [value, time] = limit.split(':');
|
||||
const rateLimitControl = {
|
||||
value,
|
||||
time
|
||||
value: Number(value),
|
||||
time: Number(time)
|
||||
};
|
||||
result.push(rateLimitControl);
|
||||
}
|
||||
@ -128,7 +128,7 @@ export function stringToRateLimitsArray(rateLimits: string): Array<RateLimits> {
|
||||
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);
|
||||
result = result.concat(rateLimits[i].value.toString(), ':', rateLimits[i].time.toString());
|
||||
if ((rateLimits.length > 1) && (i !== rateLimits.length - 1)) {
|
||||
result = result.concat(',');
|
||||
}
|
||||
@ -143,8 +143,8 @@ export function rateLimitsArrayToHtml(translate: TranslateService, rateLimitsArr
|
||||
});
|
||||
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> ');
|
||||
const andAlsoText = translate.instant('tenant-profile.rate-limits.and-also-less-than');
|
||||
result = rateLimitsHtml.join(` <span class="disabled">${andAlsoText}</span> `);
|
||||
} else {
|
||||
result = rateLimitsHtml[0];
|
||||
}
|
||||
|
||||
@ -5247,7 +5247,6 @@
|
||||
"add-limit": "إضافة حد",
|
||||
"advanced-settings": "الإعدادات المتقدمة",
|
||||
"edit-limit": "تعديل الحد",
|
||||
"but-less-than": "ولكن أقل من",
|
||||
"edit-transport-tenant-msg-title": "تعديل حدود معدل رسائل نقل المستأجر",
|
||||
"edit-transport-tenant-telemetry-msg-title": "تعديل حدود معدل رسائل تليمتري نقل المستأجر",
|
||||
"edit-transport-tenant-telemetry-data-points-title": "تعديل حدود معدل نقاط بيانات تليمتري نقل المستأجر",
|
||||
|
||||
@ -5640,7 +5640,6 @@
|
||||
"add-limit": "Tilføj begrænsning",
|
||||
"advanced-settings": "Avancerede indstillinger",
|
||||
"edit-limit": "Rediger begrænsning",
|
||||
"but-less-than": "men mindre end",
|
||||
"calculated-field-debug-event-rate-limit": "Fejlfindingshændelser for beregnede felter",
|
||||
"edit-calculated-field-debug-event-rate-limit": "Rediger hastighedsgrænser for fejlfindingshændelser for beregnede felter",
|
||||
"edit-transport-tenant-msg-title": "Rediger grænse for transportlejers beskeder",
|
||||
@ -9221,4 +9220,4 @@
|
||||
"zh_TW": "中文 (台灣)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5640,7 +5640,6 @@
|
||||
"add-limit": "Limit hinzufügen",
|
||||
"advanced-settings": "Erweiterte Einstellungen",
|
||||
"edit-limit": "Limit bearbeiten",
|
||||
"but-less-than": "aber weniger als",
|
||||
"calculated-field-debug-event-rate-limit": "Berechnete Feld-Debug-Ereignisse",
|
||||
"edit-calculated-field-debug-event-rate-limit": "Limit für berechnete Feld-Debug-Ereignisse bearbeiten",
|
||||
"edit-transport-tenant-msg-title": "Limit für Transport-Mieter-Nachrichten bearbeiten",
|
||||
@ -9221,4 +9220,4 @@
|
||||
"zh_TW": "chinesisch (Taiwan)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5681,9 +5681,9 @@
|
||||
"ws-limit-updates-per-session": "WS updates per session",
|
||||
"rate-limits": {
|
||||
"add-limit": "Add limit",
|
||||
"and-also-less-than": "and also less than",
|
||||
"advanced-settings": "Advanced settings",
|
||||
"edit-limit": "Edit limit",
|
||||
"but-less-than": "but less than",
|
||||
"calculated-field-debug-event-rate-limit": "Calculated field debug events",
|
||||
"edit-calculated-field-debug-event-rate-limit": "Edit calculated field debug events rate limits",
|
||||
"edit-transport-tenant-msg-title": "Edit transport tenant messages rate limits",
|
||||
@ -5723,6 +5723,7 @@
|
||||
"per-seconds": "Per seconds",
|
||||
"per-seconds-required": "Time rate is required.",
|
||||
"per-seconds-min": "Minimum value is 1.",
|
||||
"per-seconds-duplicate": "Duplicate time rate. Each time interval must be unique.",
|
||||
"rate-limits": "Rate limits",
|
||||
"remove-limit": "Remove limit",
|
||||
"transport-tenant-msg": "Transport tenant messages",
|
||||
|
||||
@ -5640,7 +5640,6 @@
|
||||
"add-limit": "Agregar límite",
|
||||
"advanced-settings": "Configuraciones avanzadas",
|
||||
"edit-limit": "Editar límite",
|
||||
"but-less-than": "pero menor que",
|
||||
"calculated-field-debug-event-rate-limit": "Eventos de depuración de campo calculado",
|
||||
"edit-calculated-field-debug-event-rate-limit": "Editar límites de eventos de depuración de campo calculado",
|
||||
"edit-transport-tenant-msg-title": "Editar límites de velocidad de mensajes de transporte del inquilino",
|
||||
@ -9221,4 +9220,4 @@
|
||||
"zh_TW": "中文 (台灣)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5640,7 +5640,6 @@
|
||||
"add-limit": "Ajouter une limite",
|
||||
"advanced-settings": "Paramètres avancés",
|
||||
"edit-limit": "Modifier la limite",
|
||||
"but-less-than": "mais inférieur à",
|
||||
"calculated-field-debug-event-rate-limit": "Événements de débogage des champs calculés",
|
||||
"edit-calculated-field-debug-event-rate-limit": "Modifier la limite des événements de débogage de champ calculé",
|
||||
"edit-transport-tenant-msg-title": "Modifier les limites de messages de transport du locataire",
|
||||
@ -9221,4 +9220,4 @@
|
||||
"zh_TW": "中文 (台灣)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5640,7 +5640,6 @@
|
||||
"add-limit": "Aggiungi limite",
|
||||
"advanced-settings": "Impostazioni avanzate",
|
||||
"edit-limit": "Modifica limite",
|
||||
"but-less-than": "ma inferiore a",
|
||||
"calculated-field-debug-event-rate-limit": "Eventi di debug del campo calcolato",
|
||||
"edit-calculated-field-debug-event-rate-limit": "Modifica i limiti di eventi di debug del campo calcolato",
|
||||
"edit-transport-tenant-msg-title": "Modifica i limiti di messaggi di trasporto del tenant",
|
||||
@ -9221,4 +9220,4 @@
|
||||
"zh_TW": "中文 (台灣)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5131,7 +5131,6 @@
|
||||
"add-limit": "Add limit",
|
||||
"advanced-settings": "Advanced settings",
|
||||
"edit-limit": "Edit limit",
|
||||
"but-less-than": "but less than",
|
||||
"edit-transport-tenant-msg-title": "Edit transport tenant messages rate limits",
|
||||
"edit-transport-tenant-telemetry-msg-title": "Edit transport tenant telemetry messages rate limits",
|
||||
"edit-transport-tenant-telemetry-data-points-title": "Edit transport tenant telemetry data points rate limits",
|
||||
|
||||
@ -5164,7 +5164,6 @@
|
||||
"add-limit": "Limiet toevoegen",
|
||||
"advanced-settings": "Geavanceerde instellingen",
|
||||
"edit-limit": "Limiet bewerken",
|
||||
"but-less-than": "maar minder dan",
|
||||
"edit-transport-tenant-msg-title": "Snelheidslimieten voor berichten van transporttenants bewerken",
|
||||
"edit-transport-tenant-telemetry-msg-title": "Snelheidslimieten voor telemetrie berichten van transporttenants bewerken",
|
||||
"edit-transport-tenant-telemetry-data-points-title": "Snelheidslimieten voor telemetrie gegevenspunten van transporttenants bewerken",
|
||||
|
||||
@ -5148,7 +5148,6 @@
|
||||
"add-limit": "Dodaj limit",
|
||||
"advanced-settings": "Zaawansowane ustawienia",
|
||||
"edit-limit": "Edytuj limit",
|
||||
"but-less-than": "ale mniej niż",
|
||||
"edit-transport-tenant-msg-title": "Edytuj limity szybkości wiadomości tenanta transportu",
|
||||
"edit-transport-tenant-telemetry-msg-title": "Edytuj limity szybkości komunikatów telemetrycznych Tenanta transportu",
|
||||
"edit-transport-tenant-telemetry-data-points-title": "Edytuj limity szybkości punktów danych telemetrycznych Tenanta transportu",
|
||||
|
||||
@ -4675,7 +4675,6 @@
|
||||
"add-limit": "添加限制",
|
||||
"advanced-settings": "高级设置",
|
||||
"edit-limit": "编辑限制",
|
||||
"but-less-than": "但小于",
|
||||
"edit-transport-tenant-msg-title": "编辑传输租户消息速率限制",
|
||||
"edit-transport-tenant-telemetry-msg-title": "编辑传输租户遥测消息速率限制",
|
||||
"edit-transport-tenant-telemetry-data-points-title": "编辑传输租户遥测数据点速率限制",
|
||||
|
||||
@ -3048,7 +3048,6 @@
|
||||
"add-limit": "增加限制",
|
||||
"advanced-settings": "進階設定",
|
||||
"edit-limit": "編輯限制",
|
||||
"but-less-than": "但小於",
|
||||
"edit-transport-tenant-msg-title": "編輯傳輸租戶訊息速率限制",
|
||||
"edit-transport-tenant-telemetry-msg-title": "編輯傳輸租戶遙測訊息速率限制",
|
||||
"edit-transport-tenant-telemetry-data-points-title": "編輯傳輸租戶遙測資料端速率限制",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user