diff --git a/ui-ngx/src/app/core/auth/auth.models.ts b/ui-ngx/src/app/core/auth/auth.models.ts
index 55af791156..1944c693ac 100644
--- a/ui-ngx/src/app/core/auth/auth.models.ts
+++ b/ui-ngx/src/app/core/auth/auth.models.ts
@@ -28,6 +28,8 @@ export interface SysParamsState {
userSettings: UserSettings;
maxResourceSize: number;
maxDebugModeDurationMinutes: number;
+ maxDataPointsPerRollingArg: number;
+ maxArgumentsPerCF: number;
ruleChainDebugPerTenantLimitsConfiguration?: string;
}
diff --git a/ui-ngx/src/app/core/auth/auth.reducer.ts b/ui-ngx/src/app/core/auth/auth.reducer.ts
index a460cf35bb..3ecf70074c 100644
--- a/ui-ngx/src/app/core/auth/auth.reducer.ts
+++ b/ui-ngx/src/app/core/auth/auth.reducer.ts
@@ -31,6 +31,8 @@ const emptyUserAuthState: AuthPayload = {
persistDeviceStateToTelemetry: false,
mobileQrEnabled: false,
maxResourceSize: 0,
+ maxArgumentsPerCF: 0,
+ maxDataPointsPerRollingArg: 0,
maxDebugModeDurationMinutes: 0,
userSettings: initialUserSettings
};
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html
index 96dff1c1be..6bab01f976 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html
@@ -119,9 +119,22 @@
}
-
-
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss
index c4efe323c6..877a749afa 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.scss
@@ -30,6 +30,12 @@
}
}
+ .max-args-warning {
+ .mat-icon {
+ color: #FAA405;
+ }
+ }
+
.tb-form-table-row-cell-buttons {
--mat-badge-legacy-small-size-container-size: 8px;
--mat-badge-small-size-container-overlap-offset: -5px;
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts
index 2537f34059..e3b19503af 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.ts
@@ -55,6 +55,9 @@ import { TbPopoverComponent } from '@shared/components/popover.component';
import { TbTableDatasource } from '@shared/components/table/table-datasource.abstract';
import { EntityService } from '@core/http/entity.service';
import { MatSort } from '@angular/material/sort';
+import { getCurrentAuthState } from '@core/auth/auth.selectors';
+import { Store } from '@ngrx/store';
+import { AppState } from '@core/core.state';
@Component({
selector: 'tb-calculated-field-arguments-table',
@@ -93,6 +96,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
readonly ArgumentEntityType = ArgumentEntityType;
readonly ArgumentType = ArgumentType;
readonly CalculatedFieldType = CalculatedFieldType;
+ readonly maxArgumentsPerCF = getCurrentAuthState(this.store).maxArgumentsPerCF;
private popoverComponent: TbPopoverComponent;
private propagateChange: (argumentsObj: Record) => void = () => {};
@@ -105,6 +109,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces
private renderer: Renderer2,
private entityService: EntityService,
private destroyRef: DestroyRef,
+ private store: Store
) {
this.argumentsFormArray.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => {
this.updateEntityNameMap(value);
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html
index 0695b9d2b9..7e0f87a12e 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html
@@ -78,7 +78,7 @@
{{ 'calculated-fields.expression' | translate }}
@if (fieldFormGroup.get('type').value === CalculatedFieldType.SIMPLE) {
-
+
@if (configFormGroup.get('expressionSIMPLE').errors && configFormGroup.get('expressionSIMPLE').touched) {
@if (configFormGroup.get('expressionSIMPLE').hasError('required')) {
@@ -89,6 +89,8 @@
{{ 'calculated-fields.hint.expression-max-length' | translate }}
}
+ } @else {
+ {{ 'calculated-fields.hint.expression' | translate }}
}
} @else {
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss
index 900758761c..0e994ed825 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.scss
@@ -40,7 +40,7 @@
&-key {
color: #C52F00;
}
- &-ts, &-time-window, &-values, &-value {
+ &-ts, &-time-window, &-values, &-value, &-func {
color: #7214D0;
}
&-start-ts, &-end-ts, &-limit {
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html
index 72bc85a48f..566a433545 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html
@@ -166,10 +166,19 @@
formControlName="timeWindow"
/>
-
+ @if (maxDataPointsPerRollingArg) {
+
+ }
}
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss
index 1f7c084d08..773489ee60 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.scss
@@ -28,9 +28,7 @@ $panel-width: 520px;
min-width: 120px;
}
}
-}
-:host ::ng-deep {
.limit-field-row {
@media screen and (max-width: $panel-width) {
display: flex;
@@ -42,7 +40,9 @@ $panel-width: 520px;
}
}
}
+}
+:host ::ng-deep {
.time-interval-field {
.advanced-input {
flex-direction: column;
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts
index 93b8f897ce..9d9614ba28 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts
@@ -38,7 +38,9 @@ import { EntityFilter } from '@shared/models/query/query.models';
import { AliasFilterType } from '@shared/models/alias.models';
import { merge } from 'rxjs';
import { MINUTE } from '@shared/models/time/time.models';
-import { TimeService } from '@core/services/time.service';
+import { getCurrentAuthState } from '@core/auth/auth.selectors';
+import { AppState } from '@core/core.state';
+import { Store } from '@ngrx/store';
@Component({
selector: 'tb-calculated-field-argument-panel',
@@ -58,7 +60,8 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>();
- readonly defaultLimit = Math.max(this.timeService.getMinDatapointsLimit(), Math.floor(this.timeService.getMaxDatapointsLimit() / 10));
+ readonly maxDataPointsPerRollingArg = getCurrentAuthState(this.store).maxDataPointsPerRollingArg;
+ readonly defaultLimit = Math.floor(this.maxDataPointsPerRollingArg / 10);
argumentFormGroup = this.fb.group({
argumentName: ['', [Validators.required, this.uniqNameRequired(), Validators.pattern(charsWithNumRegex), Validators.maxLength(255)]],
@@ -72,7 +75,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
scope: [{ value: AttributeScope.SERVER_SCOPE, disabled: true }, [Validators.required]],
}),
defaultValue: ['', [Validators.pattern(noLeadTrailSpacesRegex)]],
- limit: [this.defaultLimit],
+ limit: [{ value: this.defaultLimit, disabled: !this.maxDataPointsPerRollingArg }],
timeWindow: [MINUTE * 15],
});
@@ -96,7 +99,7 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit {
private fb: FormBuilder,
private cd: ChangeDetectorRef,
private popover: TbPopoverComponent,
- private timeService: TimeService
+ private store: Store
) {
this.observeEntityFilterChanges();
this.observeEntityTypeChanges()
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html
index 57234aa692..cda99f6c09 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html
@@ -45,7 +45,7 @@
[scriptLanguage]="ScriptLanguage.TBEL"
[editorCompleter]="data.argumentsEditorCompleter"
resultType="object"
- helpId="calculated-field/test-expression_fn"
+ helpId="calculated-field/expression_fn"
/>
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.scss b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.scss
index 298ab64e26..2187b47e0d 100644
--- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.scss
+++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.scss
@@ -78,7 +78,7 @@
&-key {
color: #C52F00;
}
- &-ts, &-time-window, &-values, &-value {
+ &-ts, &-time-window, &-values, &-value, &-func {
color: #7214D0;
}
&-start-ts, &-end-ts, &-limit {
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
index 9f1839afec..64d5039914 100644
--- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
+++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
@@ -229,6 +229,92 @@
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts
index 4cce34c502..b1d6652e4a 100644
--- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts
+++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts
@@ -118,7 +118,13 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
edgeEventRateLimits: [null, []],
edgeEventRateLimitsPerEdge: [null, []],
edgeUplinkMessagesRateLimits: [null, []],
- edgeUplinkMessagesRateLimitsPerEdge: [null, []]
+ edgeUplinkMessagesRateLimitsPerEdge: [null, []],
+ maxCalculatedFieldsPerEntity: [null, [Validators.required, Validators.min(0)]],
+ maxArgumentsPerCF: [null, [Validators.required, Validators.min(0)]],
+ maxDataPointsPerRollingArg: [null, [Validators.required, Validators.min(0)]],
+ maxStateSizeInKBytes: [null, [Validators.required, Validators.min(0)]],
+ calculatedFieldDebugEventsRateLimit: [null, []],
+ maxSingleValueArgumentSizeInKBytes: [null, [Validators.required, Validators.min(0)]],
});
this.defaultTenantProfileConfigurationFormGroup.get('smsEnabled').valueChanges.pipe(
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts
index ab50c967bf..f09f950ee7 100644
--- a/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts
+++ b/ui-ngx/src/app/modules/home/components/profile/tenant/rate-limits/rate-limits.models.ts
@@ -45,7 +45,8 @@ export enum RateLimitsType {
EDGE_EVENTS_RATE_LIMIT = 'EDGE_EVENTS_RATE_LIMIT',
EDGE_EVENTS_PER_EDGE_RATE_LIMIT = 'EDGE_EVENTS_PER_EDGE_RATE_LIMIT',
EDGE_UPLINK_MESSAGES_RATE_LIMIT = 'EDGE_UPLINK_MESSAGES_RATE_LIMIT',
- EDGE_UPLINK_MESSAGES_PER_EDGE_RATE_LIMIT = 'EDGE_UPLINK_MESSAGES_PER_EDGE_RATE_LIMIT'
+ EDGE_UPLINK_MESSAGES_PER_EDGE_RATE_LIMIT = 'EDGE_UPLINK_MESSAGES_PER_EDGE_RATE_LIMIT',
+ CALCULATED_FIELD_DEBUG_EVENT_RATE_LIMIT = 'CALCULATED_FIELD_DEBUG_EVENT_RATE_LIMIT',
}
export const rateLimitsLabelTranslationMap = new Map(
@@ -74,6 +75,7 @@ export const rateLimitsLabelTranslationMap = new Map(
[RateLimitsType.EDGE_EVENTS_PER_EDGE_RATE_LIMIT, 'tenant-profile.rate-limits.edge-events-per-edge-rate-limit'],
[RateLimitsType.EDGE_UPLINK_MESSAGES_RATE_LIMIT, 'tenant-profile.rate-limits.edge-uplink-messages-rate-limit'],
[RateLimitsType.EDGE_UPLINK_MESSAGES_PER_EDGE_RATE_LIMIT, 'tenant-profile.rate-limits.edge-uplink-messages-per-edge-rate-limit'],
+ [RateLimitsType.CALCULATED_FIELD_DEBUG_EVENT_RATE_LIMIT, 'tenant-profile.rate-limits.calculated-field-debug-event-rate-limit'],
]
);
@@ -103,6 +105,7 @@ export const rateLimitsDialogTitleTranslationMap = new Map =
+ ['max', 'min', 'mean', 'std', 'median', 'count', 'last', 'first', 'sum'].map(funcName => ({
+ token: 'tb.calculated-field-func',
+ regex: `\\b${funcName}\\b`,
+ next: 'no_regex'
+ }));
+
const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = {
calculatedFieldRollingArgumentValue: [
dotOperatorHighlightRule,
@@ -368,6 +523,7 @@ const calculatedFieldRollingArgumentValueHighlightRules: AceHighlightRules = {
regex: /timeWindow/,
next: 'calculatedFieldRollingArgumentTimeWindow'
},
+ ...calculatedFieldRollingArgumentValueFunctionsHighlightRules,
endGroupHighlightRule
],
}
diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts
index 23c2d95762..38ff63e3c6 100644
--- a/ui-ngx/src/app/shared/models/tenant.model.ts
+++ b/ui-ngx/src/app/shared/models/tenant.model.ts
@@ -95,6 +95,13 @@ export interface DefaultTenantProfileConfiguration {
rpcTtlDays: number;
queueStatsTtlDays: number;
ruleEngineExceptionsTtlDays: number;
+
+ maxCalculatedFieldsPerEntity: number;
+ maxArgumentsPerCF: number;
+ maxDataPointsPerRollingArg: number;
+ maxStateSizeInKBytes: number;
+ maxSingleValueArgumentSizeInKBytes: number;
+ calculatedFieldDebugEventsRateLimit: string;
}
export type TenantProfileConfigurations = DefaultTenantProfileConfiguration;
@@ -148,7 +155,13 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan
alarmsTtlDays: 0,
rpcTtlDays: 0,
queueStatsTtlDays: 0,
- ruleEngineExceptionsTtlDays: 0
+ ruleEngineExceptionsTtlDays: 0,
+ maxCalculatedFieldsPerEntity: 0,
+ maxArgumentsPerCF: 0,
+ maxDataPointsPerRollingArg: 0,
+ maxStateSizeInKBytes: 0,
+ maxSingleValueArgumentSizeInKBytes: 0,
+ calculatedFieldDebugEventsRateLimit: ''
};
configuration = {...defaultConfiguration, type: TenantProfileType.DEFAULT};
break;
diff --git a/ui-ngx/src/assets/help/en_US/calculated-field/test-expression_fn.md b/ui-ngx/src/assets/help/en_US/calculated-field/test-expression_fn.md
deleted file mode 100644
index f8173dc528..0000000000
--- a/ui-ngx/src/assets/help/en_US/calculated-field/test-expression_fn.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json
index 9aff79102b..1163024e90 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -1068,7 +1068,9 @@
"argument-name-pattern": "Argument name is invalid.",
"argument-name-duplicate": "Argument with such name already exists.",
"argument-name-max-length": "Argument name should be less than 256 characters.",
- "argument-type-required": "Argument type is required."
+ "argument-type-required": "Argument type is required.",
+ "max-args": "Maximum number of arguments reached.",
+ "expression": "Default expression demonstrates how to transform a temperature from Fahrenheit to Celsius."
}
},
"confirm-on-exit": {
@@ -5474,6 +5476,7 @@
"entities": "Entities",
"rule-engine": "Rule Engine",
"time-to-live": "Time-to-live",
+ "calculated-fields": "Calculated fields",
"alarms-and-notifications": "Alarms and notifications",
"ota-files-in-bytes": "Files",
"ws-title": "WS",
@@ -5526,6 +5529,21 @@
"tenant-entity-import-rate-limit": "Entity version load",
"tenant-notification-request-rate-limit": "Notification requests",
"tenant-notification-requests-per-rule-rate-limit": "Notification requests per notification rule",
+ "max-calculated-fields": "Maximum number of calculated fields per entity",
+ "max-calculated-fields-range": "Maximum number of calculated fields per entity can't be negative",
+ "max-calculated-fields-required": "Maximum number of calculated fields per entity is required",
+ "max-data-points-per-rolling-arg": "Maximum number of data points in a time series rolling arguments",
+ "max-data-points-per-rolling-arg-range": "Maximum number of data points in a time series rolling arguments can't be negative",
+ "max-data-points-per-rolling-arg-required": "Maximum number of data points in a time series rolling arguments is required",
+ "max-arguments-per-cf": "Maximum number of arguments per calculated field",
+ "max-arguments-per-cf-range": "Maximum number of arguments per calculated field can't be negative",
+ "max-arguments-per-cf-required": "Maximum number of arguments per calculated field is required",
+ "max-state-size": "Maximum size of the state in KB",
+ "max-state-size-range": "Maximum size of the state in KB can't be negative",
+ "max-state-size-required": "Maximum size of the state in KB is required",
+ "max-value-argument-size": "Maximum size of the single value argument in KB",
+ "max-value-argument-size-range": "Maximum size of the single value argument in KB can't be negative",
+ "max-value-argument-size-required": "Maximum size of the single value argument in KB is required",
"max-transport-messages": "Transport messages maximum number",
"max-transport-messages-required": "Transport messages maximum number is required.",
"max-transport-messages-range": "Transport messages maximum number can't be negative",
@@ -5597,6 +5615,8 @@
"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",
"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",