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:
Viacheslav Klimov 2025-06-02 12:36:44 +03:00 committed by GitHub
commit b0b682f6a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 81 additions and 74 deletions

View File

@ -17,31 +17,33 @@
--> -->
<section class="tb-rate-limits-form" [formGroup]="rateLimitsListFormGroup"> <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="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> @if($index > 0) {
tenant-profile.rate-limits.but-less-than <div class="tb-rate-limits-operation" translate>tenant-profile.rate-limits.and-also-less-than</div>
</div> }
<div class="flex flex-1 flex-row gap-2"> <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> <mat-label translate>tenant-profile.rate-limits.number-of-messages</mat-label>
<input matInput placeholder="{{ 'tenant-profile.rate-limits.number-of-messages' | translate }}" <input matInput placeholder="{{ 'tenant-profile.rate-limits.number-of-messages' | translate }}"
type="number" min="1" step="1" formControlName="value" required> type="number" min="1" step="1" formControlName="value" required>
<mat-error *ngIf="rateLimit.get('value').hasError('required')"> <mat-hint></mat-hint>
{{ 'tenant-profile.rate-limits.number-of-messages-required' | translate }} @if (rateLimit.get('value').hasError('required')) {
</mat-error> <mat-error translate>tenant-profile.rate-limits.number-of-messages-required</mat-error>
<mat-error *ngIf="rateLimit.get('value').hasError('min')"> } @else if(rateLimit.get('value').hasError('min')) {
{{ 'tenant-profile.rate-limits.number-of-messages-min' | translate }} <mat-error translate>tenant-profile.rate-limits.number-of-messages-min</mat-error>
</mat-error> }
</mat-form-field> </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> <mat-label translate>tenant-profile.rate-limits.per-seconds</mat-label>
<input matInput placeholder="{{ 'tenant-profile.rate-limits.per-seconds' | translate }}" <input matInput placeholder="{{ 'tenant-profile.rate-limits.per-seconds' | translate }}"
type="number" min="1" step="1" formControlName="time" required> type="number" min="1" step="1" formControlName="time" required>
<mat-error *ngIf="rateLimit.get('time').hasError('required')"> <mat-hint></mat-hint>
{{ 'tenant-profile.rate-limits.per-seconds-required' | translate }} @if (rateLimit.get('time').hasError('required')) {
</mat-error> <mat-error translate>tenant-profile.rate-limits.per-seconds-required</mat-error>
<mat-error *ngIf="rateLimit.get('time').hasError('min')"> } @else if (rateLimit.get('time').hasError('min')) {
{{ 'tenant-profile.rate-limits.per-seconds-min' | translate }} <mat-error translate>tenant-profile.rate-limits.per-seconds-min</mat-error>
</mat-error> } @else if (rateLimit.get('time').hasError('duplicateTime')) {
<mat-error translate>tenant-profile.rate-limits.per-seconds-duplicate</mat-error>
}
</mat-form-field> </mat-form-field>
<button mat-icon-button type="button" color="primary" <button mat-icon-button type="button" color="primary"
class="tb-rate-limits-button" class="tb-rate-limits-button"

View File

@ -18,7 +18,7 @@
:host { :host {
.tb-rate-limits-form { .tb-rate-limits-form {
@media #{$mat-gt-sm} { @media #{$mat-gt-sm} {
min-width: 600px; min-width: 620px;
} }
} }

View File

@ -14,22 +14,23 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { Component, DestroyRef, forwardRef, Input, OnInit } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
UntypedFormArray, FormArray,
UntypedFormBuilder, FormBuilder,
UntypedFormGroup, FormControl,
FormGroup,
NG_VALIDATORS, NG_VALIDATORS,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
ValidationErrors, ValidationErrors,
Validator, Validator,
ValidatorFn,
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
import { Subject, Subscription } from 'rxjs';
import { RateLimits, rateLimitsArrayToString, stringToRateLimitsArray } from './rate-limits.models'; import { RateLimits, rateLimitsArrayToString, stringToRateLimitsArray } from './rate-limits.models';
import { isDefinedAndNotNull } from '@core/utils'; import { isDefinedAndNotNull } from '@core/utils';
import { takeUntil } from 'rxjs/operators'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({ @Component({
selector: 'tb-rate-limits-list', 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; @Input() disabled: boolean;
rateLimitsListFormGroup: UntypedFormGroup; rateLimitsListFormGroup: FormGroup;
rateLimitsArray: Array<RateLimits>; 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 { ngOnInit(): void {
this.rateLimitsListFormGroup = this.fb.group({ this.rateLimitsListFormGroup = this.fb.group({
rateLimits: this.fb.array([]) rateLimits: this.fb.array([])
}); });
this.rateLimitsListFormGroup.valueChanges this.rateLimitsListFormGroup.valueChanges
.pipe(takeUntil(this.destroy$)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((value) => { .subscribe((value) => {
this.updateView(value?.rateLimits); this.updateView(value?.rateLimits ?? []);
} }
); );
} }
public removeRateLimits(index: number) { public removeRateLimits(index: number) {
(this.rateLimitsListFormGroup.get('rateLimits') as UntypedFormArray).removeAt(index); this.rateLimitsFormArray.removeAt(index);
} }
public addRateLimits() { public addRateLimits() {
this.rateLimitsFormArray.push(this.fb.group({ this.rateLimitsFormArray.push(this.fb.group({
value: [null, [Validators.required]], value: [null, [Validators.required]],
time: [null, [Validators.required]] time: [null, [Validators.required, this.uniqTimeRequired()]]
})); }));
} }
get rateLimitsFormArray(): UntypedFormArray { get rateLimitsFormArray(): FormArray<FormGroup> {
return this.rateLimitsListFormGroup.get('rateLimits') as UntypedFormArray; return this.rateLimitsListFormGroup.get('rateLimits') as FormArray<FormGroup>;
} }
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
this.propagateChange = fn; this.propagateChange = fn;
} }
registerOnTouched(fn: any): void { registerOnTouched(_fn: any): void {
} }
setDisabledState?(isDisabled: boolean): void { setDisabledState?(isDisabled: boolean): void {
@ -111,26 +112,26 @@ export class RateLimitsListComponent implements ControlValueAccessor, Validator,
} }
writeValue(rateLimits: string) { writeValue(rateLimits: string) {
const rateLimitsControls: Array<UntypedFormGroup> = []; const rateLimitsControls: Array<FormGroup> = [];
if (rateLimits) { if (rateLimits) {
const rateLimitsArray = rateLimits.split(','); this.rateLimitsArray = stringToRateLimitsArray(rateLimits);
for (let i = 0; i < rateLimitsArray.length; i++) { this.rateLimitsArray.forEach((rateLimit) => {
const [value, time] = rateLimitsArray[i].split(':');
const rateLimitsControl = this.fb.group({ const rateLimitsControl = this.fb.group({
value: [value, [Validators.required]], value: [rateLimit.value, [Validators.required]],
time: [time, [Validators.required]] time: [rateLimit.time, [Validators.required, this.uniqTimeRequired()]]
}); });
if (this.disabled) { if (this.disabled) {
rateLimitsControl.disable(); rateLimitsControl.disable();
} }
rateLimitsControls.push(rateLimitsControl); rateLimitsControls.push(rateLimitsControl);
} })
} else {
this.rateLimitsArray = null;
} }
this.rateLimitsListFormGroup.setControl('rateLimits', this.fb.array(rateLimitsControls), {emitEvent: false}); 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) { if (rateLimitsArray.length > 0) {
const notNullRateLimits = rateLimitsArray.filter(rateLimits => const notNullRateLimits = rateLimitsArray.filter(rateLimits =>
isDefinedAndNotNull(rateLimits.value) && isDefinedAndNotNull(rateLimits.time) isDefinedAndNotNull(rateLimits.value) && isDefinedAndNotNull(rateLimits.time)
@ -144,8 +145,22 @@ export class RateLimitsListComponent implements ControlValueAccessor, Validator,
} }
} }
ngOnDestroy() { private uniqTimeRequired(): ValidatorFn {
this.destroy$.next(); return (control: FormControl) => {
this.destroy$.complete(); 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;
};
} }
} }

View File

@ -17,8 +17,8 @@
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
export interface RateLimits { export interface RateLimits {
value: string; value: number;
time: string; time: number;
} }
export enum RateLimitsType { export enum RateLimitsType {
@ -113,11 +113,11 @@ export function stringToRateLimitsArray(rateLimits: string): Array<RateLimits> {
const result: Array<RateLimits> = []; const result: Array<RateLimits> = [];
if (rateLimits?.length > 0) { if (rateLimits?.length > 0) {
const rateLimitsArrays = rateLimits.split(','); const rateLimitsArrays = rateLimits.split(',');
for (let i = 0; i < rateLimitsArrays.length; i++) { for (const limit of rateLimitsArrays) {
const [value, time] = rateLimitsArrays[i].split(':'); const [value, time] = limit.split(':');
const rateLimitControl = { const rateLimitControl = {
value, value: Number(value),
time time: Number(time)
}; };
result.push(rateLimitControl); result.push(rateLimitControl);
} }
@ -128,7 +128,7 @@ export function stringToRateLimitsArray(rateLimits: string): Array<RateLimits> {
export function rateLimitsArrayToString(rateLimits: Array<RateLimits>): string { export function rateLimitsArrayToString(rateLimits: Array<RateLimits>): string {
let result = ''; let result = '';
for (let i = 0; i < rateLimits.length; i++) { 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)) { if ((rateLimits.length > 1) && (i !== rateLimits.length - 1)) {
result = result.concat(','); result = result.concat(',');
} }
@ -143,8 +143,8 @@ export function rateLimitsArrayToHtml(translate: TranslateService, rateLimitsArr
}); });
let result: string; let result: string;
if (rateLimitsHtml.length > 1) { if (rateLimitsHtml.length > 1) {
const butLessThanText = translate.instant('tenant-profile.rate-limits.but-less-than'); const andAlsoText = translate.instant('tenant-profile.rate-limits.and-also-less-than');
result = rateLimitsHtml.join(' <span class="disabled">' + butLessThanText + '</span> '); result = rateLimitsHtml.join(` <span class="disabled">${andAlsoText}</span> `);
} else { } else {
result = rateLimitsHtml[0]; result = rateLimitsHtml[0];
} }

View File

@ -5247,7 +5247,6 @@
"add-limit": "إضافة حد", "add-limit": "إضافة حد",
"advanced-settings": "الإعدادات المتقدمة", "advanced-settings": "الإعدادات المتقدمة",
"edit-limit": "تعديل الحد", "edit-limit": "تعديل الحد",
"but-less-than": "ولكن أقل من",
"edit-transport-tenant-msg-title": "تعديل حدود معدل رسائل نقل المستأجر", "edit-transport-tenant-msg-title": "تعديل حدود معدل رسائل نقل المستأجر",
"edit-transport-tenant-telemetry-msg-title": "تعديل حدود معدل رسائل تليمتري نقل المستأجر", "edit-transport-tenant-telemetry-msg-title": "تعديل حدود معدل رسائل تليمتري نقل المستأجر",
"edit-transport-tenant-telemetry-data-points-title": "تعديل حدود معدل نقاط بيانات تليمتري نقل المستأجر", "edit-transport-tenant-telemetry-data-points-title": "تعديل حدود معدل نقاط بيانات تليمتري نقل المستأجر",

View File

@ -5640,7 +5640,6 @@
"add-limit": "Tilføj begrænsning", "add-limit": "Tilføj begrænsning",
"advanced-settings": "Avancerede indstillinger", "advanced-settings": "Avancerede indstillinger",
"edit-limit": "Rediger begrænsning", "edit-limit": "Rediger begrænsning",
"but-less-than": "men mindre end",
"calculated-field-debug-event-rate-limit": "Fejlfindingshændelser for beregnede felter", "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-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", "edit-transport-tenant-msg-title": "Rediger grænse for transportlejers beskeder",

View File

@ -5640,7 +5640,6 @@
"add-limit": "Limit hinzufügen", "add-limit": "Limit hinzufügen",
"advanced-settings": "Erweiterte Einstellungen", "advanced-settings": "Erweiterte Einstellungen",
"edit-limit": "Limit bearbeiten", "edit-limit": "Limit bearbeiten",
"but-less-than": "aber weniger als",
"calculated-field-debug-event-rate-limit": "Berechnete Feld-Debug-Ereignisse", "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-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", "edit-transport-tenant-msg-title": "Limit für Transport-Mieter-Nachrichten bearbeiten",

View File

@ -5681,9 +5681,9 @@
"ws-limit-updates-per-session": "WS updates per session", "ws-limit-updates-per-session": "WS updates per session",
"rate-limits": { "rate-limits": {
"add-limit": "Add limit", "add-limit": "Add limit",
"and-also-less-than": "and also less than",
"advanced-settings": "Advanced settings", "advanced-settings": "Advanced settings",
"edit-limit": "Edit limit", "edit-limit": "Edit limit",
"but-less-than": "but less than",
"calculated-field-debug-event-rate-limit": "Calculated field debug events", "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-calculated-field-debug-event-rate-limit": "Edit calculated field debug events rate limits",
"edit-transport-tenant-msg-title": "Edit transport tenant messages rate limits", "edit-transport-tenant-msg-title": "Edit transport tenant messages rate limits",
@ -5723,6 +5723,7 @@
"per-seconds": "Per seconds", "per-seconds": "Per seconds",
"per-seconds-required": "Time rate is required.", "per-seconds-required": "Time rate is required.",
"per-seconds-min": "Minimum value is 1.", "per-seconds-min": "Minimum value is 1.",
"per-seconds-duplicate": "Duplicate time rate. Each time interval must be unique.",
"rate-limits": "Rate limits", "rate-limits": "Rate limits",
"remove-limit": "Remove limit", "remove-limit": "Remove limit",
"transport-tenant-msg": "Transport tenant messages", "transport-tenant-msg": "Transport tenant messages",

View File

@ -5640,7 +5640,6 @@
"add-limit": "Agregar límite", "add-limit": "Agregar límite",
"advanced-settings": "Configuraciones avanzadas", "advanced-settings": "Configuraciones avanzadas",
"edit-limit": "Editar límite", "edit-limit": "Editar límite",
"but-less-than": "pero menor que",
"calculated-field-debug-event-rate-limit": "Eventos de depuración de campo calculado", "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-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", "edit-transport-tenant-msg-title": "Editar límites de velocidad de mensajes de transporte del inquilino",

View File

@ -5640,7 +5640,6 @@
"add-limit": "Ajouter une limite", "add-limit": "Ajouter une limite",
"advanced-settings": "Paramètres avancés", "advanced-settings": "Paramètres avancés",
"edit-limit": "Modifier la limite", "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", "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-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", "edit-transport-tenant-msg-title": "Modifier les limites de messages de transport du locataire",

View File

@ -5640,7 +5640,6 @@
"add-limit": "Aggiungi limite", "add-limit": "Aggiungi limite",
"advanced-settings": "Impostazioni avanzate", "advanced-settings": "Impostazioni avanzate",
"edit-limit": "Modifica limite", "edit-limit": "Modifica limite",
"but-less-than": "ma inferiore a",
"calculated-field-debug-event-rate-limit": "Eventi di debug del campo calcolato", "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-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", "edit-transport-tenant-msg-title": "Modifica i limiti di messaggi di trasporto del tenant",

View File

@ -5131,7 +5131,6 @@
"add-limit": "Add limit", "add-limit": "Add limit",
"advanced-settings": "Advanced settings", "advanced-settings": "Advanced settings",
"edit-limit": "Edit limit", "edit-limit": "Edit limit",
"but-less-than": "but less than",
"edit-transport-tenant-msg-title": "Edit transport tenant messages rate limits", "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-msg-title": "Edit transport tenant telemetry messages rate limits",
"edit-transport-tenant-telemetry-data-points-title": "Edit transport tenant telemetry data points rate limits", "edit-transport-tenant-telemetry-data-points-title": "Edit transport tenant telemetry data points rate limits",

View File

@ -5164,7 +5164,6 @@
"add-limit": "Limiet toevoegen", "add-limit": "Limiet toevoegen",
"advanced-settings": "Geavanceerde instellingen", "advanced-settings": "Geavanceerde instellingen",
"edit-limit": "Limiet bewerken", "edit-limit": "Limiet bewerken",
"but-less-than": "maar minder dan",
"edit-transport-tenant-msg-title": "Snelheidslimieten voor berichten van transporttenants bewerken", "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-msg-title": "Snelheidslimieten voor telemetrie berichten van transporttenants bewerken",
"edit-transport-tenant-telemetry-data-points-title": "Snelheidslimieten voor telemetrie gegevenspunten van transporttenants bewerken", "edit-transport-tenant-telemetry-data-points-title": "Snelheidslimieten voor telemetrie gegevenspunten van transporttenants bewerken",

View File

@ -5148,7 +5148,6 @@
"add-limit": "Dodaj limit", "add-limit": "Dodaj limit",
"advanced-settings": "Zaawansowane ustawienia", "advanced-settings": "Zaawansowane ustawienia",
"edit-limit": "Edytuj limit", "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-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-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", "edit-transport-tenant-telemetry-data-points-title": "Edytuj limity szybkości punktów danych telemetrycznych Tenanta transportu",

View File

@ -4675,7 +4675,6 @@
"add-limit": "添加限制", "add-limit": "添加限制",
"advanced-settings": "高级设置", "advanced-settings": "高级设置",
"edit-limit": "编辑限制", "edit-limit": "编辑限制",
"but-less-than": "但小于",
"edit-transport-tenant-msg-title": "编辑传输租户消息速率限制", "edit-transport-tenant-msg-title": "编辑传输租户消息速率限制",
"edit-transport-tenant-telemetry-msg-title": "编辑传输租户遥测消息速率限制", "edit-transport-tenant-telemetry-msg-title": "编辑传输租户遥测消息速率限制",
"edit-transport-tenant-telemetry-data-points-title": "编辑传输租户遥测数据点速率限制", "edit-transport-tenant-telemetry-data-points-title": "编辑传输租户遥测数据点速率限制",

View File

@ -3048,7 +3048,6 @@
"add-limit": "增加限制", "add-limit": "增加限制",
"advanced-settings": "進階設定", "advanced-settings": "進階設定",
"edit-limit": "編輯限制", "edit-limit": "編輯限制",
"but-less-than": "但小於",
"edit-transport-tenant-msg-title": "編輯傳輸租戶訊息速率限制", "edit-transport-tenant-msg-title": "編輯傳輸租戶訊息速率限制",
"edit-transport-tenant-telemetry-msg-title": "編輯傳輸租戶遙測訊息速率限制", "edit-transport-tenant-telemetry-msg-title": "編輯傳輸租戶遙測訊息速率限制",
"edit-transport-tenant-telemetry-data-points-title": "編輯傳輸租戶遙測資料端速率限制", "edit-transport-tenant-telemetry-data-points-title": "編輯傳輸租戶遙測資料端速率限制",