Browse Source

Merge branch 'rc' of github.com:thingsboard/thingsboard into release-4.3

pull/15304/head
Viacheslav Klimov 9 months ago
parent
commit
fb5883b772
  1. 2
      application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java
  2. 5
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java
  3. 6
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java
  4. 8
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java
  5. 2
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java
  6. 7
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/geofencing/GeofencingCalculatedFieldState.java
  7. 4
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java
  8. 10
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/cf/CalculatedFieldEdgeProcessor.java
  9. 3
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java
  10. 22
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasUseLatestTsConfig.java
  11. 9
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java
  12. 2
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java
  13. 3
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java
  14. 11
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/geofencing/GeofencingCalculatedFieldConfiguration.java
  15. 2
      ui-ngx/src/app/core/services/calculated-field-form.service.ts
  16. 2
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-list.component.html
  17. 12
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-list.component.ts
  18. 2
      ui-ngx/src/app/modules/home/components/calculated-fields/components/simple-configuration/simple-configuration.component.ts
  19. 2
      ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.ts
  20. 2
      ui-ngx/src/app/modules/home/pages/security/security.component.html
  21. 34
      ui-ngx/src/app/modules/home/pages/security/security.component.ts
  22. 2
      ui-ngx/src/app/shared/components/country-autocomplete.component.ts
  23. 69
      ui-ngx/src/app/shared/components/time-unit-input.component.ts

2
application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java

@ -384,7 +384,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
EntityId mainId,
MultipleTbCallback parentCallback,
TriConsumer<EntityId, CalculatedFieldCtx, TbCallback> relationAction) {
if (isMyPartition(mainId, parentCallback)) {
if (!isMyPartition(mainId, parentCallback)) {
return;
}
List<CalculatedFieldCtx> cfsByEntityIdAndProfile = getCalculatedFieldsByEntityIdAndProfile(mainId);

5
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java

@ -21,6 +21,7 @@ import lombok.Getter;
import lombok.Setter;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId;
@ -142,8 +143,8 @@ public abstract class BaseCalculatedFieldState implements CalculatedFieldState,
protected void validateNewEntry(String key, ArgumentEntry newEntry) {
}
protected ObjectNode toSimpleResult(boolean useLatestTs, ObjectNode valuesNode) {
if (!useLatestTs) {
protected ObjectNode toResultNode(ObjectNode valuesNode) {
if (ctx.getOutput().getType() == OutputType.ATTRIBUTES || !ctx.isUseLatestTs()) {
return valuesNode;
}
long latestTs = getLatestTimestamp();

6
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java

@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.cf.configuration.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.ExpressionBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.HasUseLatestTsConfig;
import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
@ -187,7 +188,6 @@ public class CalculatedFieldCtx implements Closeable {
.collect(Collectors.toList());
if (argBasedConfig instanceof ExpressionBasedCalculatedFieldConfiguration expressionBasedConfig) {
this.expression = expressionBasedConfig.getExpression();
this.useLatestTs = CalculatedFieldType.SIMPLE.equals(calculatedField.getType()) && ((SimpleCalculatedFieldConfiguration) argBasedConfig).isUseLatestTs();
}
if (calculatedField.getConfiguration() instanceof GeofencingCalculatedFieldConfiguration geofencingConfig) {
geofencingConfig.getZoneGroups().forEach((zoneGroupName, config) -> {
@ -209,8 +209,8 @@ public class CalculatedFieldCtx implements Closeable {
if (calculatedField.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration scheduledConfig) {
this.scheduledUpdateIntervalMillis = scheduledConfig.isScheduledUpdateEnabled() ? TimeUnit.SECONDS.toMillis(scheduledConfig.getScheduledUpdateInterval()) : DISABLED_INTERVAL_VALUE;
}
if (calculatedField.getConfiguration() instanceof RelatedEntitiesAggregationCalculatedFieldConfiguration aggConfig) {
this.useLatestTs = aggConfig.isUseLatestTs();
if (calculatedField.getConfiguration() instanceof HasUseLatestTsConfig hasUseLatestTsConfig) {
this.useLatestTs = hasUseLatestTsConfig.isUseLatestTs();
}
this.systemContext = systemContext;
this.tbelInvokeService = systemContext.getTbelInvokeService();

8
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java

@ -22,13 +22,13 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.EqualsAndHashCode;
import net.objecthunter.exp4j.Expression;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.NumberUtils;
import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.cf.CalculatedFieldResult;
import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult;
import org.thingsboard.common.util.NumberUtils;
import java.util.Map;
@ -53,7 +53,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
Output output = ctx.getOutput();
Object result = NumberUtils.roundResult(expressionResult, output.getDecimalsByDefault());
JsonNode outputResult = createResultJson(ctx.isUseLatestTs(), output.getName(), result);
JsonNode outputResult = createResultJson(output.getName(), result);
return Futures.immediateFuture(TelemetryCalculatedFieldResult.builder()
.outputStrategy(output.getStrategy())
@ -63,7 +63,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
.build());
}
private JsonNode createResultJson(boolean useLatestTs, String outputName, Object result) {
private JsonNode createResultJson(String outputName, Object result) {
ObjectNode valuesNode = JacksonUtil.newObjectNode();
if (result instanceof Double doubleValue) {
valuesNode.put(outputName, doubleValue);
@ -72,7 +72,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
} else {
valuesNode.set(outputName, JacksonUtil.valueToTree(result));
}
return toSimpleResult(useLatestTs, valuesNode);
return toResultNode(valuesNode);
}
@Override

2
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java

@ -201,7 +201,7 @@ public class RelatedEntitiesAggregationCalculatedFieldState extends BaseCalculat
.outputStrategy(output.getStrategy())
.type(output.getType())
.scope(output.getScope())
.result(toSimpleResult(ctx.isUseLatestTs(), aggResult))
.result(toResultNode(aggResult))
.build());
} else {
return Futures.immediateFuture(TelemetryCalculatedFieldResult.EMPTY);

7
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/geofencing/GeofencingCalculatedFieldState.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.cf.ctx.state.geofencing;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@ -136,7 +135,7 @@ public class GeofencingCalculatedFieldState extends BaseCalculatedFieldState imp
.outputStrategy(ctx.getOutput().getStrategy())
.type(outputType)
.scope(ctx.getOutput().getScope())
.result(toResultNode(outputType, valuesNode))
.result(toResultNode(valuesNode))
.build();
if (relationFutures.isEmpty()) {
return Futures.immediateFuture(result);
@ -186,10 +185,6 @@ public class GeofencingCalculatedFieldState extends BaseCalculatedFieldState imp
}
}
private JsonNode toResultNode(OutputType outputType, ObjectNode valuesNode) {
return toSimpleResult(outputType == OutputType.TIME_SERIES, valuesNode);
}
private GeofencingEvalResult aggregateZoneGroup(List<GeofencingEvalResult> zoneResults) {
boolean nowInside = zoneResults.stream().anyMatch(r -> INSIDE.equals(r.status()));
boolean prevInside = zoneResults.stream()

4
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java

@ -24,7 +24,6 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.util.CollectionsUtil;
import org.thingsboard.server.service.cf.CalculatedFieldProcessingService;
@ -171,8 +170,7 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState
throw new IllegalArgumentException("Unsupported argument type: " + argumentEntry.getType() + " detected for argument: " + outputKey + ". " +
"Only Latest telemetry or Attribute arguments supported for 'Arguments Only' propagation mode!");
});
ObjectNode result = toSimpleResult(output.getType() == OutputType.TIME_SERIES, valuesNode);
telemetryCfBuilder.result(result);
telemetryCfBuilder.result(toResultNode(valuesNode));
return telemetryCfBuilder.build();
}

10
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/cf/CalculatedFieldEdgeProcessor.java

@ -25,6 +25,7 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -47,6 +48,9 @@ import org.thingsboard.server.service.edge.EdgeMsgConstructorUtils;
import java.util.UUID;
import static org.thingsboard.server.common.data.cf.CalculatedFieldType.SCRIPT;
import static org.thingsboard.server.common.data.cf.CalculatedFieldType.SIMPLE;
@Slf4j
@Component
@TbCoreComponent
@ -91,7 +95,7 @@ public class CalculatedFieldEdgeProcessor extends BaseCalculatedFieldProcessor i
switch (edgeEvent.getAction()) {
case ADDED, UPDATED -> {
CalculatedField calculatedField = edgeCtx.getCalculatedFieldService().findById(edgeEvent.getTenantId(), calculatedFieldId);
if (calculatedField != null) {
if (calculatedField != null && isValidCfToSend(calculatedField.getType(), edgeVersion)) {
UpdateMsgType msgType = getUpdateMsgType(edgeEvent.getAction());
CalculatedFieldUpdateMsg calculatedFieldUpdateMsg = EdgeMsgConstructorUtils.constructCalculatedFieldUpdatedMsg(msgType, calculatedField);
return DownlinkMsg.newBuilder()
@ -111,6 +115,10 @@ public class CalculatedFieldEdgeProcessor extends BaseCalculatedFieldProcessor i
return null;
}
private boolean isValidCfToSend(CalculatedFieldType type, EdgeVersion edgeVersion) {
return edgeVersion.getNumber() >= EdgeVersion.V_4_3_0.getNumber() || (type == SIMPLE || type == SCRIPT);
}
@Override
public EdgeEventType getEdgeEventType() {
return EdgeEventType.CALCULATED_FIELD;

3
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.cf.configuration;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.Map;
@ -24,6 +25,8 @@ public abstract class BaseCalculatedFieldConfiguration implements ExpressionBase
protected Map<String, Argument> arguments;
protected String expression;
@NotNull
protected Output output;
@Override

22
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasUseLatestTsConfig.java

@ -0,0 +1,22 @@
/**
* Copyright © 2016-2026 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.
*/
package org.thingsboard.server.common.data.cf.configuration;
public interface HasUseLatestTsConfig {
boolean isUseLatestTs();
}

9
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.cf.configuration;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -27,7 +28,7 @@ import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements HasRelationPathLevel {
public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements HasRelationPathLevel, HasUseLatestTsConfig {
public static final String PROPAGATION_CONFIG_ARGUMENT = "propagationCtx";
@ -37,6 +38,12 @@ public class PropagationCalculatedFieldConfiguration extends BaseCalculatedField
private boolean applyExpressionToResolvedArguments;
@Override
@JsonIgnore
public boolean isUseLatestTs() {
return output.getType() == OutputType.TIME_SERIES;
}
@Override
public CalculatedFieldType getType() {
return CalculatedFieldType.PROPAGATION;

2
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java

@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType;
@Data
@EqualsAndHashCode(callSuper = true)
public class SimpleCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ExpressionBasedCalculatedFieldConfiguration {
public class SimpleCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ExpressionBasedCalculatedFieldConfiguration, HasUseLatestTsConfig {
private boolean useLatestTs;

3
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java

@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType;
import org.thingsboard.server.common.data.cf.configuration.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.HasRelationPathLevel;
import org.thingsboard.server.common.data.cf.configuration.HasUseLatestTsConfig;
import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.relation.RelationPathLevel;
@ -30,7 +31,7 @@ import org.thingsboard.server.common.data.relation.RelationPathLevel;
import java.util.Map;
@Data
public class RelatedEntitiesAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasRelationPathLevel {
public class RelatedEntitiesAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasRelationPathLevel, HasUseLatestTsConfig {
@NotNull
private RelationPathLevel relation;

11
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/geofencing/GeofencingCalculatedFieldConfiguration.java

@ -22,7 +22,9 @@ import lombok.Data;
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
import org.thingsboard.server.common.data.cf.configuration.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.HasUseLatestTsConfig;
import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.EntityId;
@ -35,7 +37,7 @@ import java.util.Set;
import static java.util.stream.Collectors.toSet;
@Data
public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration {
public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasUseLatestTsConfig {
@Valid
@NotNull
@ -48,8 +50,15 @@ public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCal
private boolean scheduledUpdateEnabled;
private int scheduledUpdateInterval;
@NotNull
private Output output;
@Override
@JsonIgnore
public boolean isUseLatestTs() {
return output.getType() == OutputType.TIME_SERIES;
}
@Override
public CalculatedFieldType getType() {
return CalculatedFieldType.GEOFENCING;

2
ui-ngx/src/app/core/services/calculated-field-form.service.ts

@ -71,7 +71,7 @@ export class CalculatedFieldFormService {
takeUntilDestroyed(destroyRef)
).subscribe(([prevType, nextType]) => {
const shouldCheck = isEditActive ? isEditActive() : true;
if (shouldCheck) {
if (shouldCheck && prevType !== nextType) {
if (![CalculatedFieldType.SIMPLE, CalculatedFieldType.SCRIPT].includes(prevType) ||
![CalculatedFieldType.SIMPLE, CalculatedFieldType.SCRIPT].includes(nextType)) {
form.get('configuration').setValue({} as CalculatedFieldConfiguration, { emitEvent: false });

2
ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-list.component.html

@ -41,7 +41,7 @@
<div class="flex max-w-92% flex-full flex-col">
<div class="flex flex-row items-center justify-start">
<div class="filters-text flex-1">{{ filterControl.value?.argument }}</div>
<div class="filters-text flex-1">{{ FilterPredicateTypeTranslationMap.get(filterControl.value?.valueType) | translate }}</div>
<div class="filters-text flex-1">{{ entityKeyValueTypes.get(entityKeyValueTypeEnum[filterControl.value?.valueType]).name | translate }}</div>
<button mat-icon-button color="primary" class="tb-budge-button"
type="button"
(click)="editFilter(index, readonly)"

12
ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-list.component.ts

@ -30,7 +30,8 @@ import { Observable } from 'rxjs';
import {
ComplexOperation,
complexOperationTranslationMap,
EntityKeyValueType
EntityKeyValueType,
entityKeyValueTypesMap
} from '@shared/models/query/query.models';
import { MatDialog } from '@angular/material/dialog';
import { deepClone } from '@core/utils';
@ -38,11 +39,7 @@ import {
AlarmRuleFilterDialogComponent,
AlarmRuleFilterDialogData
} from "@home/components/alarm-rules/filter/alarm-rule-filter-dialog.component";
import {
AlarmRuleFilter,
areFilterAndPredicateArgumentsValid,
FilterPredicateTypeTranslationMap
} from "@shared/models/alarm-rule.models";
import { AlarmRuleFilter, areFilterAndPredicateArgumentsValid } from "@shared/models/alarm-rule.models";
import { CalculatedFieldArgument } from "@shared/models/calculated-field.models";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
@ -83,7 +80,8 @@ export class AlarmRuleFilterListComponent implements ControlValueAccessor, Valid
areFilterAndPredicateArgumentsValid = areFilterAndPredicateArgumentsValid;
complexOperationTranslationMap = complexOperationTranslationMap;
FilterPredicateTypeTranslationMap = FilterPredicateTypeTranslationMap
entityKeyValueTypes = entityKeyValueTypesMap;
entityKeyValueTypeEnum = EntityKeyValueType;
private propagateChange = (v: any) => { };

2
ui-ngx/src/app/modules/home/components/calculated-fields/components/simple-configuration/simple-configuration.component.ts

@ -200,7 +200,7 @@ export class SimpleConfigurationComponent implements ControlValueAccessor, Valid
}
private toggleScopeByOutputType(): void {
if (this.isScript || this.simpleConfiguration.get('output').value.type === OutputType.Attribute) {
if (this.isScript || this.simpleConfiguration.get('output').value.type === OutputType.Attribute || this.disabled) {
this.simpleConfiguration.get('useLatestTs').disable({emitEvent: false});
} else {
this.simpleConfiguration.get('useLatestTs').enable({emitEvent: false});

2
ui-ngx/src/app/modules/home/pages/admin/two-factor-auth-settings.component.ts

@ -69,6 +69,8 @@ export class TwoFactorAuthSettingsComponent extends PageComponent implements OnI
this.build2faSettingsForm();
this.twoFaService.getTwoFaSettings().subscribe((setting) => {
this.setAuthConfigFormValue(setting);
this.twoFaFormGroup.markAsUntouched();
this.twoFaFormGroup.markAsPristine();
});
}

2
ui-ngx/src/app/modules/home/pages/security/security.component.html

@ -54,7 +54,7 @@
<mat-label translate>profile.current-password</mat-label>
<input matInput type="password" name="current-password" formControlName="currentPassword" autocomplete="current-password"/>
<tb-toggle-password [class.!hidden]="!changePassword.get('currentPassword').dirty && !changePassword.get('currentPassword').touched" matSuffix></tb-toggle-password>
<mat-error *ngIf="changePassword.get('currentPassword').hasError('passwordsNotMatch')">
<mat-error *ngIf="changePassword.get('currentPassword').hasError('differencePassword')">
{{ 'security.password-requirement.incorrect-password-try-again' | translate }}
</mat-error>
</mat-form-field>

34
ui-ngx/src/app/modules/home/pages/security/security.component.ts

@ -333,22 +333,24 @@ export class SecurityComponent extends PageComponent implements OnInit, OnDestro
onChangePassword(form: FormGroupDirective): void {
if (this.changePassword.valid) {
this.authService.changePassword(this.changePassword.get('currentPassword').value,
this.changePassword.get('newPassword').value, {ignoreErrors: true}).subscribe(() => {
this.discardChanges(form);
},
(error) => {
if (error.status === 400 && error.error.message === 'Current password doesn\'t match!') {
this.changePassword.get('currentPassword').setErrors({differencePassword: true});
} else if (error.status === 400 && error.error.message.startsWith('Password must')) {
this.loadPasswordPolicy();
} else if (error.status === 400 && error.error.message.startsWith('Password was already used')) {
this.changePassword.get('newPassword').setErrors({alreadyUsed: error.error.message});
} else {
this.store.dispatch(new ActionNotificationShow({
message: error.error.message,
type: 'error',
target: 'changePassword'
}));
this.changePassword.get('newPassword').value, {ignoreErrors: true}).subscribe({
next: () => {
this.discardChanges(form);
},
error: (error) => {
if (error.status === 400 && error.error.message === 'Current password doesn\'t match!') {
this.changePassword.get('currentPassword').setErrors({ differencePassword: true });
} else if (error.status === 400 && error.error.message.startsWith('Password must')) {
this.loadPasswordPolicy();
} else if (error.status === 400 && error.error.message.startsWith('Password was already used')) {
this.changePassword.get('newPassword').setErrors({ alreadyUsed: error.error.message });
} else {
this.store.dispatch(new ActionNotificationShow({
message: error.error.message,
type: 'error',
target: 'changePassword'
}));
}
}
});
} else {

2
ui-ngx/src/app/shared/components/country-autocomplete.component.ts

@ -130,7 +130,7 @@ export class CountryAutocompleteComponent implements OnInit, OnChanges, ControlV
if (changes.required) {
const requiredChanges = changes.required;
if (requiredChanges.currentValue !== requiredChanges.previousValue) {
if (requiredChanges.currentValue) {
if (this.required) {
this.countryFormGroup.get('country').addValidators(Validators.required);
} else {
this.countryFormGroup.get('country').removeValidators(Validators.required);

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

@ -134,39 +134,13 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
if (isDefinedAndNotNull(this.maxTime)) {
this.updatedAllowTimeUnitInterval(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) {
validators.push(Validators.required);
}
if (this.maxTime) {
validators.push((control: AbstractControl) =>
Validators.max(Math.floor(this.maxTime / this.timeIntervalsInSec.get(this.timeInputForm.get('timeUnit').value)))(control)
);
}
if (isDefinedAndNotNull(this.minTime)) {
this.minValueValidator = this.minValue;
validators.push((control: AbstractControl) =>
Validators.min(this.minValueValidator)(control)
);
}
if (isDefinedAndNotNull(this.stepMultipleOf) && this.stepMultipleOf > 0) {
validators.push(this.createStepMultipleOfValidator());
}
timeControl.setValidators(validators);
timeControl.updateValueAndValidity({ emitEvent: false });
}
this.refreshTimeValidators();
this.timeInputForm.get('timeUnit').valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {
if (isDefinedAndNotNull(this.minTime)) {
this.minValueValidator = this.minValue;
}
this.timeInputForm.get('time').updateValueAndValidity({onlySelf: true});
this.refreshTimeValidators();
this.timeInputForm.get('time').markAsTouched({onlySelf: true});
});
@ -201,11 +175,10 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
if (isDefinedAndNotNull(this.maxTime)) {
this.timeUnits = Object.values(TimeUnit).filter(item => item !== TimeUnit.MILLISECONDS) as TimeUnit[];
this.updatedAllowTimeUnitInterval(this.maxTime);
this.timeInputForm.get('time').updateValueAndValidity({emitEvent: false});
}
}
if (propName === 'minTime') {
this.minValueValidator = isDefinedAndNotNull(this.minTime) ? this.minValue : 0;
if (['minTime', 'maxTime', 'required', 'stepMultipleOf'].includes(propName)) {
this.refreshTimeValidators();
}
}
}
@ -312,4 +285,38 @@ export class TimeUnitInputComponent implements ControlValueAccessor, Validator,
}
}
private refreshTimeValidators() {
const timeControl = this.timeInputForm.get('time');
if (!timeControl) return;
const currentUnit = this.timeInputForm.get('timeUnit')?.value as TimeUnit;
if (!currentUnit) return;
const secondsInUnit = this.timeIntervalsInSec.get(currentUnit) ?? 1;
const validators: ValidatorFn[] = [Validators.pattern(/^\d*$/)];
if (this.required) {
validators.push(Validators.required);
}
if (isDefinedAndNotNull(this.minTime)) {
this.minValueValidator = Math.ceil(this.minTime / secondsInUnit);
validators.push(Validators.min(this.minValueValidator));
} else {
this.minValueValidator = 0;
validators.push(Validators.min(this.minValueValidator));
}
if (isDefinedAndNotNull(this.maxTime)) {
const maxInCurrentUnit = Math.floor(this.maxTime / secondsInUnit);
validators.push(Validators.max(maxInCurrentUnit));
}
if (isDefinedAndNotNull(this.stepMultipleOf) && this.stepMultipleOf > 0) {
validators.push(this.createStepMultipleOfValidator());
}
timeControl.setValidators(validators);
timeControl.updateValueAndValidity({ onlySelf: true, emitEvent: false });
}
}

Loading…
Cancel
Save