Browse Source

UI: Add minAggregationIntervalInSecForCF config and add stepMultipleOf in time-unit

pull/14253/head
Vladyslav_Prykhodko 10 months ago
parent
commit
6add362380
  1. 1
      ui-ngx/src/app/core/auth/auth.models.ts
  2. 1
      ui-ngx/src/app/core/auth/auth.reducer.ts
  3. 21
      ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.html
  4. 13
      ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.ts
  5. 32
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html
  6. 1
      ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts
  7. 2
      ui-ngx/src/app/shared/components/time-unit-input.component.html
  8. 49
      ui-ngx/src/app/shared/components/time-unit-input.component.ts
  9. 3
      ui-ngx/src/app/shared/models/calculated-field.models.ts
  10. 2
      ui-ngx/src/app/shared/models/tenant.model.ts
  11. 13
      ui-ngx/src/assets/locale/locale.constant-en_US.json

1
ui-ngx/src/app/core/auth/auth.models.ts

@ -32,6 +32,7 @@ export interface SysParamsState {
maxDataPointsPerRollingArg: number;
maxArgumentsPerCF: number;
minAllowedDeduplicationIntervalInSecForCF: number;
minAggregationIntervalInSecForCF: number;
minAllowedScheduledUpdateIntervalInSecForCF: number;
maxRelationLevelPerCfArgument: number;
ruleChainDebugPerTenantLimitsConfiguration?: string;

1
ui-ngx/src/app/core/auth/auth.reducer.ts

@ -34,6 +34,7 @@ const emptyUserAuthState: AuthPayload = {
maxResourceSize: 0,
maxArgumentsPerCF: 0,
minAllowedDeduplicationIntervalInSecForCF: 0,
minAggregationIntervalInSecForCF: 0,
minAllowedScheduledUpdateIntervalInSecForCF: 0,
maxRelationLevelPerCfArgument: 0,
maxDataPointsPerRollingArg: 0,

21
ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.html

@ -62,13 +62,16 @@
</div>
@if (entityAggregationConfiguration.get('interval.type').value === AggIntervalType.CUSTOM) {
<tb-time-unit-input required
[minTime]="60"
[minTime]="minAggregationIntervalInSecForCF"
[stepMultipleOf]="DayInSec"
sameWidthInputs
appearance="outline"
subscriptSizing="dynamic"
containerClass="flex gap-3"
labelText="{{ 'calculated-fields.aggregate-interval-value' | translate }}"
minErrorText="{{ 'calculated-fields.aggregate-interval-value-min' | translate }}"
minErrorText="{{ 'calculated-fields.aggregate-interval-value-min' | translate : {sec: minAggregationIntervalInSecForCF} }}"
requiredText="{{ 'calculated-fields.aggregate-interval-value-required' | translate }}"
stepMultipleOfErrorText="Must be 1 day"
formControlName="durationSec">
</tb-time-unit-input>
}
@ -84,6 +87,7 @@
sameWidthInputs
appearance="outline"
subscriptSizing="dynamic"
containerClass="flex gap-3"
labelText="{{ 'calculated-fields.entity-aggregation.offset-value' | translate }}"
minErrorText="{{ 'calculated-fields.entity-aggregation.offset-value-min' | translate }}"
requiredText="{{ 'calculated-fields.entity-aggregation.offset-value-required' | translate }}"
@ -104,24 +108,13 @@
[minTime]="60"
sameWidthInputs
appearance="outline"
containerClass="flex gap-3"
labelText="{{ 'calculated-fields.entity-aggregation.duration' | translate }}"
minErrorText="{{ 'calculated-fields.entity-aggregation.duration-min' | translate }}"
hintText="{{ 'calculated-fields.entity-aggregation.duration-hint' | translate }}"
requiredText="{{ 'calculated-fields.entity-aggregation.duration-required' | translate }}"
formControlName="duration">
</tb-time-unit-input>
<tb-time-unit-input required
[minTime]="30"
[maxTime]="entityAggregationConfiguration.get('watermark.duration').value"
sameWidthInputs
appearance="outline"
labelText="{{ 'calculated-fields.entity-aggregation.check-interval' | translate }}"
hintText="{{ 'calculated-fields.entity-aggregation.check-interval-hint' | translate }}"
minErrorText="{{ 'calculated-fields.entity-aggregation.check-interval-min' | translate }}"
maxErrorText="{{ 'calculated-fields.entity-aggregation.check-interval-max' | translate }}"
requiredText="{{ 'calculated-fields.entity-aggregation.check-interval-required' | translate }}"
formControlName="checkInterval">
</tb-time-unit-input>
</ng-container>
}
</div>

13
ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.ts

@ -37,8 +37,11 @@ import {
} from '@shared/models/calculated-field.models';
import { map } from 'rxjs/operators';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { HOUR, MINUTE, SECOND } from '@shared/models/time/time.models';
import { DAY, HOUR, MINUTE, SECOND } from '@shared/models/time/time.models';
import { isDefinedAndNotNull } from '@core/utils';
import { getCurrentAuthState } from '@core/auth/auth.selectors';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
interface CalculatedFieldEntityAggregationConfigurationValue extends CalculatedFieldEntityAggregationConfiguration {
interval: AggInterval & {allowOffsetSec?: boolean};
@ -72,6 +75,8 @@ export class EntityAggregationComponentComponent implements ControlValueAccessor
@Input({required: true})
entityName: string;
readonly minAggregationIntervalInSecForCF = getCurrentAuthState(this.store).minAggregationIntervalInSecForCF;
readonly DayInSec = DAY / SECOND;
entityAggregationConfiguration = this.fb.group({
arguments: this.fb.control({}, notEmptyObjectValidator()),
@ -79,14 +84,13 @@ export class EntityAggregationComponentComponent implements ControlValueAccessor
interval: this.fb.group({
type: [AggIntervalType.HOUR],
tz: ['', Validators.required],
durationSec: [HOUR/SECOND, Validators.required],
durationSec: [this.minAggregationIntervalInSecForCF, Validators.required],
allowOffsetSec: [false],
offsetSec: [MINUTE/SECOND, Validators.required],
}),
allowWatermark: [false],
watermark: this.fb.group({
duration: [HOUR/SECOND, Validators.required],
checkInterval: [10 * MINUTE / SECOND, Validators.required],
}),
output: this.fb.control<CalculatedFieldOutput>({
type: OutputType.Timeseries,
@ -103,7 +107,8 @@ export class EntityAggregationComponentComponent implements ControlValueAccessor
private propagateChange: (config: CalculatedFieldEntityAggregationConfiguration) => void = () => { };
constructor(private fb: FormBuilder) {
constructor(private fb: FormBuilder,
private store: Store<AppState>) {
this.entityAggregationConfiguration.get('interval.type').valueChanges.pipe(
takeUntilDestroyed()

32
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html

@ -342,17 +342,17 @@
</div>
<div class="flex flex-1 flex-row xs:flex-col gt-xs:gap-4">
<mat-form-field class="mat-block flex-1" appearance="fill" subscriptSizing="dynamic">
<mat-label translate>tenant-profile.relation-search-entity-limit</mat-label>
<input matInput required min="1" step="1"
formControlName="maxRelatedEntitiesToReturnPerCfArgument"
<mat-label translate>tenant-profile.min-allowed-aggregation-interval</mat-label>
<input matInput required min="0" step="1"
formControlName="minAggregationIntervalInSecForCF"
type="number">
<mat-error *ngIf="tenantProfileConfigurationForm.get('maxRelatedEntitiesToReturnPerCfArgument').hasError('required')">
{{ 'tenant-profile.relation-search-entity-limit-required' | translate}}
<mat-error *ngIf="tenantProfileConfigurationForm.get('minAggregationIntervalInSecForCF').hasError('required')">
{{ 'tenant-profile.min-allowed-aggregation-interval-required' | translate}}
</mat-error>
<mat-error *ngIf="tenantProfileConfigurationForm.get('maxRelatedEntitiesToReturnPerCfArgument').hasError('min')">
{{ 'tenant-profile.relation-search-entity-limit-range' | translate}}
<mat-error *ngIf="tenantProfileConfigurationForm.get('minAggregationIntervalInSecForCF').hasError('min')">
{{ 'tenant-profile.min-allowed-aggregation-interval-range' | translate}}
</mat-error>
<mat-hint translate>tenant-profile.relation-search-entity-limit-hint</mat-hint>
<mat-hint></mat-hint>
</mat-form-field>
<mat-form-field class="mat-block flex-1" appearance="fill" subscriptSizing="dynamic">
<mat-label translate>tenant-profile.min-allowed-deduplication-interval</mat-label>
@ -368,6 +368,22 @@
<mat-hint></mat-hint>
</mat-form-field>
</div>
<div class="flex flex-1 flex-row xs:flex-col gt-xs:gap-4">
<mat-form-field class="mat-block flex-1" appearance="fill" subscriptSizing="dynamic">
<mat-label translate>tenant-profile.relation-search-entity-limit</mat-label>
<input matInput required min="1" step="1"
formControlName="maxRelatedEntitiesToReturnPerCfArgument"
type="number">
<mat-error *ngIf="tenantProfileConfigurationForm.get('maxRelatedEntitiesToReturnPerCfArgument').hasError('required')">
{{ 'tenant-profile.relation-search-entity-limit-required' | translate}}
</mat-error>
<mat-error *ngIf="tenantProfileConfigurationForm.get('maxRelatedEntitiesToReturnPerCfArgument').hasError('min')">
{{ 'tenant-profile.relation-search-entity-limit-range' | translate}}
</mat-error>
<mat-hint translate>tenant-profile.relation-search-entity-limit-hint</mat-hint>
</mat-form-field>
<div class="flex-1"></div>
</div>
</ng-template>
</mat-expansion-panel>
</fieldset>

1
ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts

@ -117,6 +117,7 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA
maxArgumentsPerCF: [0, [Validators.required, Validators.min(0)]],
maxRelationLevelPerCfArgument: [1, [Validators.required, Validators.min(1)]],
minAllowedDeduplicationIntervalInSecForCF: [0, [Validators.required, Validators.min(0)]],
minAggregationIntervalInSecForCF: [0, [Validators.required, Validators.min(0)]],
maxRelatedEntitiesToReturnPerCfArgument: [1, [Validators.required, Validators.min(1)]],
minAllowedScheduledUpdateIntervalInSecForCF: [0, [Validators.required, Validators.min(0)]],
maxDataPointsPerRollingArg: [0, [Validators.required, Validators.min(0)]],

2
ui-ngx/src/app/shared/components/time-unit-input.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<section [formGroup]="timeInputForm" class="flex gap-4">
<section [formGroup]="timeInputForm" [class]="containerClass">
<mat-form-field [class]="{'number': inlineField, 'max-w-66%': !inlineField && !sameWidthInputs, 'flex-full': !inlineField}"
[appearance]="inlineField ? 'outline' : appearance"
subscriptSizing="dynamic">

49
ui-ngx/src/app/shared/components/time-unit-input.component.ts

@ -23,6 +23,7 @@ import {
NG_VALUE_ACCESSOR,
ValidationErrors,
Validator,
ValidatorFn,
Validators
} from '@angular/forms';
import { TimeUnit, timeUnitTranslations } from '@home/components/rule-node/rule-node-config.models';
@ -79,6 +80,13 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
@Input()
maxErrorText: string;
@Input()
@coerceNumber()
stepMultipleOf: number;
@Input()
stepMultipleOfErrorText: string;
@Input()
subscriptSizing: SubscriptSizing = 'fixed';
@ -93,6 +101,9 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
@coerceBoolean()
sameWidthInputs: boolean = false;
@Input()
containerClass: string | string[] | Record<string, boolean | undefined | null> = "flex gap-4";
timeUnits = Object.values(TimeUnit).filter(item => item !== TimeUnit.MILLISECONDS) as TimeUnit[];
timeUnitTranslations = timeUnitTranslations;
@ -128,7 +139,7 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
this.timeUnits = this.timeUnits.filter(item => item !== TimeUnit.DAYS);
}
}
if(this.required || this.maxTime) {
if (this.required || this.maxTime || isDefinedAndNotNull(this.minTime) || this.stepMultipleOf) {
const timeControl = this.timeInputForm.get('time');
const validators = [Validators.pattern(/^\d*$/)];
if (this.required) {
@ -145,6 +156,10 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
);
}
if (isDefinedAndNotNull(this.stepMultipleOf) && this.stepMultipleOf > 0) {
validators.push(this.createStepMultipleOfValidator());
}
timeControl.setValidators(validators);
timeControl.updateValueAndValidity({ emitEvent: false });
}
@ -170,6 +185,8 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
return this.minErrorText;
} else if (this.timeInputForm.get('time').hasError('max') && this.maxErrorText) {
return this.maxErrorText;
} else if (this.timeInputForm.get('time').hasError('stepMultipleOf') && this.stepMultipleOfErrorText) {
return this.stepMultipleOfErrorText;
}
}
@ -232,4 +249,34 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
}
}
private createStepMultipleOfValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const time = control.value;
if (!isDefinedAndNotNull(time) || !isNumeric(time)) {
return null;
}
const numericTime = Number(time);
if (numericTime === 0) {
return null;
}
const timeUnit = control.parent?.get('timeUnit')?.value as TimeUnit;
if (!timeUnit) {
return null;
}
const unitInSec = this.timeIntervalsInSec.get(timeUnit);
const totalTimeInSec = numericTime * unitInSec;
const multipleOfVal = this.stepMultipleOf;
let isValid: boolean;
if (totalTimeInSec < multipleOfVal) {
isValid = (multipleOfVal % totalTimeInSec === 0);
} else {
isValid = (totalTimeInSec % multipleOfVal === 0);
}
return isValid ? null : { stepMultipleOf: true };
};
}
}

3
ui-ngx/src/app/shared/models/calculated-field.models.ts

@ -135,8 +135,7 @@ export interface CalculatedFieldEntityAggregationConfiguration {
}
export interface WatermarkConfig {
duration?: number;
checkInterval?: number;
duration: number;
}
interface BasePropagationConfiguration {

2
ui-ngx/src/app/shared/models/tenant.model.ts

@ -108,6 +108,7 @@ export interface DefaultTenantProfileConfiguration {
maxArgumentsPerCF: number;
maxRelationLevelPerCfArgument: number;
minAllowedDeduplicationIntervalInSecForCF: number;
minAggregationIntervalInSecForCF: number;
maxRelatedEntitiesToReturnPerCfArgument: number;
minAllowedScheduledUpdateIntervalInSecForCF: number;
maxDataPointsPerRollingArg: number;
@ -176,6 +177,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan
maxDataPointsPerRollingArg: 1000,
maxRelationLevelPerCfArgument: 10,
minAllowedDeduplicationIntervalInSecForCF: 3600,
minAggregationIntervalInSecForCF: 60,
maxRelatedEntitiesToReturnPerCfArgument: 100,
minAllowedScheduledUpdateIntervalInSecForCF: 0,
maxStateSizeInKBytes: 32,

13
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1195,7 +1195,8 @@
"aggregate-interval-type": "Aggregate interval type",
"aggregate-interval-value": "Aggregate interval value",
"aggregate-interval-value-required": "Aggregate interval value is required",
"aggregate-interval-value-min": "Aggregate interval value should be at least 1 minute",
"aggregate-interval-value-min": "Aggregate interval value should be at least { sec, plural, =0 {0 second} =1 {1 second} other {# seconds} }",
"aggregate-interval-value-step-multiple-of": "Aggregate interval value must be a divisor or multiple of 1 day",
"aggregate-period": {
"hour": "Hour",
"day": "Day",
@ -1220,12 +1221,7 @@
"duration": "Duration",
"duration-required": "Duration is required",
"duration-min": "Duration should be at least 1 minute",
"duration-hint": "Defines how long to wait for delayed data after the interval ends",
"check-interval": "Check for telemetry every",
"check-interval-required": "Check for telemetry every is required",
"check-interval-min": "Check interval should be at least 30 seconds",
"check-interval-max": "Check interval need be less than the duration",
"check-interval-hint": "Defines how often to recheck for late telemetry during the watermark period"
"duration-hint": "How long to wait for delayed data after the interval ends"
},
"hint": {
"arguments-simple-with-rolling": "Simple type calculated field should not contain keys with time series rolling type.",
@ -6001,6 +5997,9 @@
"min-allowed-deduplication-interval": "Min allowed deduplication interval (seconds)",
"min-allowed-deduplication-interval-range": "Min allowed deduplication interval value can't be negative",
"min-allowed-deduplication-interval-required": "Min allowed deduplication interval is required",
"min-allowed-aggregation-interval": "Min allowed aggregation interval (seconds)",
"min-allowed-aggregation-interval-range": "Min allowed aggregation interval value can't be negative",
"min-allowed-aggregation-interval-required": "Min allowed aggregation interval is required",
"min-allowed-scheduled-update-interval-required": "Min allowed update interval min number is required",
"max-state-size": "State maximum size in KB",
"max-state-size-range": "State maximum size in KB can't be negative",

Loading…
Cancel
Save