Browse Source

Merge branch 'master' into api-key

pull/14074/head
Viacheslav Klimov 7 months ago
committed by GitHub
parent
commit
4d6a31fa85
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java
  2. 9
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java
  3. 17
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java
  4. 9
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  5. 31
      application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java
  6. 17
      application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java
  7. 7
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java
  8. 4
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java
  9. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java
  10. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java
  11. 26
      common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java
  12. 5
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentTrigger.java
  13. 5
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmTrigger.java
  14. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmAssignmentNotificationRuleTriggerConfig.java
  15. 4
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmCommentNotificationRuleTriggerConfig.java
  16. 6
      common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmNotificationRuleTriggerConfig.java
  17. 13
      common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java
  18. 6
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/cf/CalculatedFieldTest.java
  19. 5
      ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules-table-config.ts
  20. 3
      ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules-table.component.ts
  21. 2
      ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-schedule.component.html
  22. 1
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.html
  23. 1
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.ts
  24. 1
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.html
  25. 1
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate-list.component.html
  26. 3
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate-list.component.ts
  27. 2
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate-value.component.html
  28. 12
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate-value.component.ts
  29. 1
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate.component.html
  30. 4
      ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate.component.ts
  31. 5
      ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts
  32. 3
      ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts
  33. 2
      ui-ngx/src/assets/help/en_US/notification/alarm.md
  34. 1
      ui-ngx/src/assets/help/en_US/notification/alarm_assignment.md
  35. 1
      ui-ngx/src/assets/help/en_US/notification/alarm_comment.md
  36. 3
      ui-ngx/src/assets/help/en_US/notification/edge_communication_failure.md
  37. 3
      ui-ngx/src/assets/help/en_US/notification/edge_connection.md
  38. 3
      ui-ngx/src/assets/help/en_US/notification/resources_shortage.md
  39. 3
      ui-ngx/src/assets/help/en_US/notification/task_processing_failure.md

1
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java

@ -62,6 +62,7 @@ public class AlarmAssignmentTriggerProcessor implements NotificationRuleTriggerP
.alarmType(alarmInfo.getType())
.alarmOriginator(alarmInfo.getOriginator())
.alarmOriginatorName(alarmInfo.getOriginatorName())
.alarmOriginatorLabel(alarmInfo.getOriginatorLabel())
.alarmSeverity(alarmInfo.getSeverity())
.alarmStatus(alarmInfo.getStatus())
.alarmCustomerId(alarmInfo.getCustomerId())

9
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.alarm.AlarmCommentType;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmStatusFilter;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.NameLabelAndCustomerDetails;
import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo;
import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentTrigger;
@ -57,11 +58,14 @@ public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProc
@Override
public RuleOriginatedNotificationInfo constructNotificationInfo(AlarmCommentTrigger trigger) {
Alarm alarm = trigger.getAlarm();
String originatorName;
String originatorName, originatorLabel;
if (alarm instanceof AlarmInfo) {
originatorName = ((AlarmInfo) alarm).getOriginatorName();
originatorLabel = ((AlarmInfo) alarm).getOriginatorLabel();
} else {
originatorName = entityService.fetchEntityName(trigger.getTenantId(), alarm.getOriginator()).orElse("");
var infoOpt = entityService.fetchNameLabelAndCustomerDetails(trigger.getTenantId(), alarm.getOriginator());
originatorName = infoOpt.map(NameLabelAndCustomerDetails::getName).orElse(null);
originatorLabel = infoOpt.map(NameLabelAndCustomerDetails::getLabel).orElse(null);
}
return AlarmCommentNotificationInfo.builder()
.comment(trigger.getComment().getComment().get("text").asText())
@ -73,6 +77,7 @@ public class AlarmCommentTriggerProcessor implements NotificationRuleTriggerProc
.alarmType(alarm.getType())
.alarmOriginator(alarm.getOriginator())
.alarmOriginatorName(originatorName)
.alarmOriginatorLabel(originatorLabel)
.alarmSeverity(alarm.getSeverity())
.alarmStatus(alarm.getStatus())
.alarmCustomerId(alarm.getCustomerId())

17
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java

@ -15,7 +15,9 @@
*/
package org.thingsboard.server.service.notification.rule.trigger;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmApiCallResult;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
@ -28,6 +30,9 @@ import org.thingsboard.server.common.data.notification.rule.trigger.config.Alarm
import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig.ClearRule;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.util.HashMap;
import java.util.Map;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains;
@ -106,15 +111,27 @@ public class AlarmTriggerProcessor implements NotificationRuleTriggerProcessor<A
alarmUpdate.isDeleted() ? "deleted" : null)
.alarmOriginator(alarmInfo.getOriginator())
.alarmOriginatorName(alarmInfo.getOriginatorName())
.alarmOriginatorLabel(alarmInfo.getOriginatorLabel())
.alarmSeverity(alarmInfo.getSeverity())
.alarmStatus(alarmInfo.getStatus())
.acknowledged(alarmInfo.isAcknowledged())
.cleared(alarmInfo.isCleared())
.alarmCustomerId(alarmInfo.getCustomerId())
.dashboardId(alarmInfo.getDashboardId())
.details(toDetailsTemplateMap(alarmInfo.getDetails()))
.build();
}
private Map<String, String> toDetailsTemplateMap(JsonNode details) {
Map<String, String> infoMap = JacksonUtil.toFlatMap(details);
Map<String, String> result = new HashMap<>();
for (Map.Entry<String, String> entry : infoMap.entrySet()) {
String key = "details." + entry.getKey();
result.put(key, entry.getValue());
}
return result;
}
@Override
public NotificationRuleTriggerType getTriggerType() {
return NotificationRuleTriggerType.ALARM;

9
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -704,9 +704,14 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
}
protected Device createDevice(String name, String accessToken) throws Exception {
return createDevice(name, "default", null, accessToken);
}
protected Device createDevice(String name, String type, String label, String accessToken) throws Exception {
Device device = new Device();
device.setName(name);
device.setType("default");
device.setType(type);
device.setLabel(label);
DeviceData deviceData = new DeviceData();
deviceData.setTransportConfiguration(new DefaultDeviceTransportConfiguration());
deviceData.setConfiguration(new DefaultDeviceConfiguration());
@ -1184,7 +1189,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
Awaitility.await("CF state for entity actor ready to refresh dynamic arguments").atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> {
CalculatedFieldState calculatedFieldState = statesMap.get(cfId);
boolean isReady = calculatedFieldState != null && ((GeofencingCalculatedFieldState) calculatedFieldState).getLastDynamicArgumentsRefreshTs()
< System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(scheduledUpdateInterval);
< System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(scheduledUpdateInterval);
log.warn("entityId {}, cfId {}, state ready to refresh == {}", entityId, cfId, isReady);
return isReady;
});

31
application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java

@ -22,9 +22,9 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.data.util.Pair;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cache.limits.RateLimitService;
import org.thingsboard.server.common.data.AttributeScope;
@ -134,7 +134,7 @@ import static org.thingsboard.server.common.data.notification.rule.trigger.confi
})
public class NotificationRuleApiTest extends AbstractNotificationApiTest {
@SpyBean
@MockitoSpyBean
private AlarmSubscriptionService alarmSubscriptionService;
@Autowired
private DefaultSystemInfoService systemInfoService;
@ -190,7 +190,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
@Test
public void testNotificationRuleProcessing_alarmTrigger() throws Exception {
String notificationSubject = "Alarm type: ${alarmType}, status: ${alarmStatus}, " +
"severity: ${alarmSeverity}, deviceId: ${alarmOriginatorId}";
"severity: ${alarmSeverity}, deviceId: ${alarmOriginatorId}, details: ${details.data}.";
String notificationText = "Status: ${alarmStatus}, severity: ${alarmSeverity}";
NotificationTemplate notificationTemplate = createNotificationTemplate(NotificationType.ALARM, notificationSubject, notificationText, NotificationDeliveryMethod.WEB);
@ -218,12 +218,12 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
clients.put(delay, userAndClient.getSecond());
}
notificationRule.setRecipientsConfig(recipientsConfig);
notificationRule = saveNotificationRule(notificationRule);
saveNotificationRule(notificationRule);
String alarmType = "myBoolIsTrue";
DeviceProfile deviceProfile = createDeviceProfileWithAlarmRules(alarmType);
Device device = createDevice("Device 1", deviceProfile.getName(), "1234");
Device device = createDevice("Device 1", deviceProfile.getName(), "label", "1234");
clients.values().forEach(wsClient -> {
wsClient.subscribeForUnreadNotifications(10).waitForReply(true);
@ -247,7 +247,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
assertThat(actualDelay).isCloseTo(expectedDelay, offset(2.0));
assertThat(notification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + AlarmStatus.ACTIVE_UNACK + ", " +
"severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase() + ", deviceId: " + device.getId());
"severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase() + ", deviceId: " + device.getId() + ", details: attribute is true.");
assertThat(notification.getText()).isEqualTo("Status: " + AlarmStatus.ACTIVE_UNACK + ", severity: " + AlarmSeverity.CRITICAL.toString().toLowerCase());
assertThat(notification.getType()).isEqualTo(NotificationType.ALARM);
@ -267,7 +267,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
wsClient.waitForUpdate(true);
Notification updatedNotification = wsClient.getLastDataUpdate().getUpdate();
assertThat(updatedNotification.getSubject()).isEqualTo("Alarm type: " + alarmType + ", status: " + expectedStatus + ", " +
"severity: " + expectedSeverity.toString().toLowerCase() + ", deviceId: " + device.getId());
"severity: " + expectedSeverity.toString().toLowerCase() + ", deviceId: " + device.getId() + ", details: attribute is true.");
assertThat(updatedNotification.getText()).isEqualTo("Status: " + expectedStatus + ", severity: " + expectedSeverity.toString().toLowerCase());
wsClient.close();
@ -293,7 +293,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
List<Notification> notifications = getMyNotifications(false, 10);
assertThat(notifications).singleElement().matches(notification -> {
return notification.getType() == NotificationType.ALARM &&
notification.getSubject().equals("New alarm 'testAlarm'");
notification.getSubject().equals("New alarm 'testAlarm'");
});
});
}
@ -488,11 +488,11 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
});
assertThat(notifications).anySatisfy(notification -> {
assertThat(notification.getText()).isEqualTo("Rate limits for REST API requests per customer " +
"exceeded for 'Customer'");
"exceeded for 'Customer'");
});
assertThat(notifications).anySatisfy(notification -> {
assertThat(notification.getText()).isEqualTo("Rate limits for notification requests " +
"per rule exceeded for '" + rule.getName() + "'");
"per rule exceeded for '" + rule.getName() + "'");
});
loginSysAdmin();
@ -513,10 +513,10 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
.notifyOn(Set.of(ASSIGNED, UNASSIGNED))
.build();
NotificationTarget target = createNotificationTarget(tenantAdminUserId);
String template = "${userEmail} ${action} alarm on ${alarmOriginatorEntityType} '${alarmOriginatorName}'. Assignee: ${assigneeEmail}";
String template = "${userEmail} ${action} alarm on ${alarmOriginatorEntityType} '${alarmOriginatorName}' with label '${alarmOriginatorLabel}'. Assignee: ${assigneeEmail}";
createNotificationRule(triggerConfig, "Test", template, target.getId());
Device device = createDevice("Device A", "123");
Device device = createDevice("Device A", "default", "test", "123");
Alarm alarm = Alarm.builder()
.tenantId(tenantId)
.originator(device.getId())
@ -533,7 +533,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
doPost("/api/alarm/" + alarmId + "/assign/" + tenantAdminUserId).andExpect(status().isOk());
}, notification -> {
assertThat(notification.getText()).isEqualTo(
TENANT_ADMIN_EMAIL + " assigned alarm on Device 'Device A'. Assignee: " + TENANT_ADMIN_EMAIL
TENANT_ADMIN_EMAIL + " assigned alarm on Device 'Device A' with label 'test'. Assignee: " + TENANT_ADMIN_EMAIL
);
});
@ -541,7 +541,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
doDelete("/api/alarm/" + alarmId + "/assign").andExpect(status().isOk());
}, notification -> {
assertThat(notification.getText()).isEqualTo(
TENANT_ADMIN_EMAIL + " unassigned alarm on Device 'Device A'. Assignee: "
TENANT_ADMIN_EMAIL + " unassigned alarm on Device 'Device A' with label 'test'. Assignee: "
);
});
}
@ -745,7 +745,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
.build();
assertThat(DefaultNotificationDeduplicationService.getDeduplicationKey(expectedTrigger, rule))
.isEqualTo("RATE_LIMITS:TENANT:" + tenantId + ":ENTITY_EXPORT_" +
target.getId() + ":ENTITY_EXPORT,TRANSPORT_MESSAGES_PER_DEVICE");
target.getId() + ":ENTITY_EXPORT,TRANSPORT_MESSAGES_PER_DEVICE");
loginTenantAdmin();
getWsClient().subscribeForUnreadNotifications(10).waitForReply();
@ -952,6 +952,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest {
argument.setRefEntityKey(new ReferencedEntityKey("createAlarm", ArgumentType.ATTRIBUTE, AttributeScope.SERVER_SCOPE));
configuration.setArguments(Map.of("createAlarm", argument));
AlarmRule alarmRule = new AlarmRule();
alarmRule.setAlarmDetails("attribute is ${bool}");
SimpleAlarmCondition condition = new SimpleAlarmCondition();
TbelAlarmConditionExpression expression = new TbelAlarmConditionExpression();
expression.setExpression("return createAlarm == true;");

17
application/src/test/java/org/thingsboard/server/service/sync/vc/VersionControlTest.java

@ -244,7 +244,7 @@ public class VersionControlTest extends AbstractControllerTest {
DeviceProfile deviceProfile = createDeviceProfile(null, null, "Device profile v1.0");
OtaPackage firmware = createOtaPackage(tenantId1, deviceProfile.getId(), OtaPackageType.FIRMWARE);
OtaPackage software = createOtaPackage(tenantId1, deviceProfile.getId(), OtaPackageType.SOFTWARE);
Device device = createDevice(null, deviceProfile.getId(), "Device v1.0", "test1", newDevice -> {
Device device = createDevice(deviceProfile.getId(), "Device v1.0", "test1", newDevice -> {
newDevice.setFirmwareId(firmware.getId());
newDevice.setSoftwareId(software.getId());
});
@ -267,7 +267,7 @@ public class VersionControlTest extends AbstractControllerTest {
createVersion("profiles", EntityType.DEVICE_PROFILE);
OtaPackage firmware = createOtaPackage(tenantId1, deviceProfile.getId(), OtaPackageType.FIRMWARE);
OtaPackage software = createOtaPackage(tenantId1, deviceProfile.getId(), OtaPackageType.SOFTWARE);
Device device = createDevice(null, deviceProfile.getId(), "Device of tenant 1", "test1", newDevice -> {
Device device = createDevice(deviceProfile.getId(), "Device of tenant 1", "test1", newDevice -> {
newDevice.setFirmwareId(firmware.getId());
newDevice.setSoftwareId(software.getId());
});
@ -528,7 +528,7 @@ public class VersionControlTest extends AbstractControllerTest {
@Test
public void testVcWithRelations_betweenTenants() throws Exception {
Asset asset = createAsset(null, null, "Asset 1");
Device device = createDevice(null, null, "Device 1", "test1");
Device device = createDevice("Device 1", "test1");
EntityRelation relation = createRelation(asset.getId(), device.getId());
String versionId = createVersion("assets and devices", EntityType.ASSET, EntityType.DEVICE, EntityType.DEVICE_PROFILE, EntityType.ASSET_PROFILE);
@ -554,11 +554,11 @@ public class VersionControlTest extends AbstractControllerTest {
@Test
public void testVcWithRelations_sameTenant() throws Exception {
Asset asset = createAsset(null, null, "Asset 1");
Device device1 = createDevice(null, null, "Device 1", "test1");
Device device1 = createDevice("Device 1", "test1");
EntityRelation relation1 = createRelation(device1.getId(), asset.getId());
String versionId = createVersion("assets", EntityType.ASSET);
Device device2 = createDevice(null, null, "Device 2", "test2");
Device device2 = createDevice("Device 2", "test2");
EntityRelation relation2 = createRelation(device2.getId(), asset.getId());
List<EntityRelation> relations = findRelationsByTo(asset.getId());
assertThat(relations).contains(relation1, relation2);
@ -591,7 +591,7 @@ public class VersionControlTest extends AbstractControllerTest {
@Test
public void testVcWithCalculatedFields_betweenTenants() throws Exception {
Asset asset = createAsset(null, null, "Asset 1");
Device device = createDevice(null, null, "Device 1", "test1");
Device device = createDevice("Device 1", "test1");
CalculatedField calculatedField = createCalculatedField("CalculatedField1", device.getId(), asset.getId());
String versionId = createVersion("calculated fields of asset and device", EntityType.ASSET, EntityType.DEVICE, EntityType.DEVICE_PROFILE, EntityType.ASSET_PROFILE);
@ -617,7 +617,7 @@ public class VersionControlTest extends AbstractControllerTest {
@Test
public void testVcWithReferencedCalculatedFields_betweenTenants() throws Exception {
Asset asset = createAsset(null, null, "Asset 1");
Device device = createDevice(null, null, "Device 1", "test1");
Device device = createDevice("Device 1", "test1");
CalculatedField deviceCalculatedField = createCalculatedField("CalculatedField1", device.getId(), asset.getId());
CalculatedField assetCalculatedField = createCalculatedField("CalculatedField2", asset.getId(), device.getId());
String versionId = createVersion("calculated fields of asset and device", EntityType.ASSET, EntityType.DEVICE, EntityType.DEVICE_PROFILE, EntityType.ASSET_PROFILE);
@ -911,9 +911,8 @@ public class VersionControlTest extends AbstractControllerTest {
login(tenantAdmin2.getEmail(), tenantAdmin2.getEmail());
}
private Device createDevice(CustomerId customerId, DeviceProfileId deviceProfileId, String name, String accessToken, Consumer<Device>... modifiers) {
private Device createDevice(DeviceProfileId deviceProfileId, String name, String accessToken, Consumer<Device>... modifiers) {
Device device = new Device();
device.setCustomerId(customerId);
device.setName(name);
device.setLabel("lbl");
device.setDeviceProfileId(deviceProfileId);

7
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmInfo.java

@ -21,11 +21,14 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serial;
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Schema
public class AlarmInfo extends Alarm {
@Serial
private static final long serialVersionUID = 2807343093519543363L;
@Getter
@ -58,8 +61,8 @@ public class AlarmInfo extends Alarm {
public AlarmInfo(AlarmInfo alarmInfo) {
super(alarmInfo);
this.originatorName = alarmInfo.originatorName;
this.originatorLabel = alarmInfo.originatorLabel;
this.originatorName = alarmInfo.getOriginatorName();
this.originatorLabel = alarmInfo.getOriginatorLabel();
this.assignee = alarmInfo.getAssignee();
}

4
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/AlarmRule.java

@ -21,6 +21,7 @@ import lombok.Data;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.validation.NoXss;
import java.io.Serial;
import java.io.Serializable;
@Schema
@ -28,6 +29,9 @@ import java.io.Serializable;
@Deprecated
public class AlarmRule implements Serializable {
@Serial
private static final long serialVersionUID = -7617427132423304707L;
@Valid
@Schema(description = "JSON object representing the alarm rule condition")
private AlarmCondition condition;

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmAssignmentNotificationInfo.java

@ -53,6 +53,7 @@ public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificati
private UUID alarmId;
private EntityId alarmOriginator;
private String alarmOriginatorName;
private String alarmOriginatorLabel;
private AlarmSeverity alarmSeverity;
private AlarmStatus alarmStatus;
private CustomerId alarmCustomerId;
@ -77,7 +78,8 @@ public class AlarmAssignmentNotificationInfo implements RuleOriginatedNotificati
"alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().getNormalName(),
"alarmOriginatorId", alarmOriginator.getId().toString(),
"alarmOriginatorName", alarmOriginatorName
"alarmOriginatorName", alarmOriginatorName,
"alarmOriginatorLabel", alarmOriginatorLabel
);
}

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmCommentNotificationInfo.java

@ -48,6 +48,7 @@ public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationI
private UUID alarmId;
private EntityId alarmOriginator;
private String alarmOriginatorName;
private String alarmOriginatorLabel;
private AlarmSeverity alarmSeverity;
private AlarmStatus alarmStatus;
private CustomerId alarmCustomerId;
@ -68,7 +69,8 @@ public class AlarmCommentNotificationInfo implements RuleOriginatedNotificationI
"alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().getNormalName(),
"alarmOriginatorId", alarmOriginator.getId().toString(),
"alarmOriginatorName", alarmOriginatorName
"alarmOriginatorName", alarmOriginatorName,
"alarmOriginatorLabel", alarmOriginatorLabel
);
}

26
common/data/src/main/java/org/thingsboard/server/common/data/notification/info/AlarmNotificationInfo.java

@ -25,11 +25,10 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.EntityId;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ -41,25 +40,28 @@ public class AlarmNotificationInfo implements RuleOriginatedNotificationInfo {
private UUID alarmId;
private EntityId alarmOriginator;
private String alarmOriginatorName;
private String alarmOriginatorLabel;
private AlarmSeverity alarmSeverity;
private AlarmStatus alarmStatus;
private boolean acknowledged;
private boolean cleared;
private CustomerId alarmCustomerId;
private DashboardId dashboardId;
private Map<String, String> details;
@Override
public Map<String, String> getTemplateData() {
return mapOf(
"alarmType", alarmType,
"action", action,
"alarmId", alarmId.toString(),
"alarmSeverity", alarmSeverity.name().toLowerCase(),
"alarmStatus", alarmStatus.toString(),
"alarmOriginatorEntityType", alarmOriginator.getEntityType().getNormalName(),
"alarmOriginatorName", alarmOriginatorName,
"alarmOriginatorId", alarmOriginator.getId().toString()
);
Map<String, String> templateData = details != null ? new HashMap<>(details) : new HashMap<>();
templateData.put("alarmType", alarmType);
templateData.put("action", action);
templateData.put("alarmId", alarmId.toString());
templateData.put("alarmSeverity", alarmSeverity.name().toLowerCase());
templateData.put("alarmStatus", alarmStatus.toString());
templateData.put("alarmOriginatorEntityType", alarmOriginator.getEntityType().getNormalName());
templateData.put("alarmOriginatorName", alarmOriginatorName);
templateData.put("alarmOriginatorLabel", alarmOriginatorLabel);
templateData.put("alarmOriginatorId", alarmOriginator.getId().toString());
return templateData;
}
@Override

5
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentTrigger.java

@ -25,10 +25,15 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.io.Serial;
@Data
@Builder
public class AlarmCommentTrigger implements NotificationRuleTrigger {
@Serial
private static final long serialVersionUID = -8614770559491757202L;
private final TenantId tenantId;
private final AlarmComment comment;
private final Alarm alarm;

5
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmTrigger.java

@ -22,10 +22,15 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType;
import java.io.Serial;
@Data
@Builder
public class AlarmTrigger implements NotificationRuleTrigger {
@Serial
private static final long serialVersionUID = -466810297904938644L;
private final TenantId tenantId;
private final AlarmApiCallResult alarmUpdate;

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmAssignmentNotificationRuleTriggerConfig.java

@ -23,6 +23,7 @@ import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import java.io.Serial;
import java.util.Set;
@Data
@ -31,6 +32,9 @@ import java.util.Set;
@Builder
public class AlarmAssignmentNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
@Serial
private static final long serialVersionUID = -5313556049809972096L;
private Set<String> alarmTypes;
private Set<AlarmSeverity> alarmSeverities;
private Set<AlarmSearchStatus> alarmStatuses;

4
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmCommentNotificationRuleTriggerConfig.java

@ -22,6 +22,7 @@ import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import java.io.Serial;
import java.util.Set;
@Data
@ -30,6 +31,9 @@ import java.util.Set;
@Builder
public class AlarmCommentNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
@Serial
private static final long serialVersionUID = -9164282098882339645L;
private Set<String> alarmTypes;
private Set<AlarmSeverity> alarmSeverities;
private Set<AlarmSearchStatus> alarmStatuses;

6
common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmNotificationRuleTriggerConfig.java

@ -23,6 +23,7 @@ import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import java.io.Serial;
import java.io.Serializable;
import java.util.Set;
@ -32,6 +33,9 @@ import java.util.Set;
@Builder
public class AlarmNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig {
@Serial
private static final long serialVersionUID = -7382883720381542344L;
private Set<String> alarmTypes;
private Set<AlarmSeverity> alarmSeverities;
@NotEmpty
@ -46,6 +50,8 @@ public class AlarmNotificationRuleTriggerConfig implements NotificationRuleTrigg
@Data
public static class ClearRule implements Serializable {
@Serial
private static final long serialVersionUID = 7922533150038105124L;
private Set<AlarmSearchStatus> alarmStatuses;
}

13
common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java

@ -41,9 +41,6 @@ import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by ashvayka on 13.01.18.
*/
@Data
@Slf4j
public final class TbMsg implements Serializable {
@ -500,11 +497,11 @@ public final class TbMsg implements Serializable {
public String toString() {
return "TbMsg.TbMsgBuilder(queueName=" + this.queueName + ", id=" + this.id + ", ts=" + this.ts +
", type=" + this.type + ", internalType=" + this.internalType + ", originator=" + this.originator +
", customerId=" + this.customerId + ", metaData=" + this.metaData + ", dataType=" + this.dataType +
", data=" + this.data + ", ruleChainId=" + this.ruleChainId + ", ruleNodeId=" + this.ruleNodeId +
", correlationId=" + this.correlationId + ", partition=" + this.partition + ", previousCalculatedFields=" + this.previousCalculatedFieldIds +
", ctx=" + this.ctx + ", callback=" + this.callback + ")";
", type=" + this.type + ", internalType=" + this.internalType + ", originator=" + this.originator +
", customerId=" + this.customerId + ", metaData=" + this.metaData + ", dataType=" + this.dataType +
", data=" + this.data + ", ruleChainId=" + this.ruleChainId + ", ruleNodeId=" + this.ruleNodeId +
", correlationId=" + this.correlationId + ", partition=" + this.partition + ", previousCalculatedFields=" + this.previousCalculatedFieldIds +
", ctx=" + this.ctx + ", callback=" + this.callback + ")";
}
}

6
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/cf/CalculatedFieldTest.java

@ -449,8 +449,7 @@ public class CalculatedFieldTest extends AbstractContainerTest {
cf.setConfigurationVersion(1);
PropagationCalculatedFieldConfiguration cfg = new PropagationCalculatedFieldConfiguration();
cfg.setDirection(EntitySearchDirection.TO);
cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
cfg.setRelation(new RelationPathLevel(EntitySearchDirection.TO, EntityRelation.CONTAINS_TYPE));
cfg.setApplyExpressionToResolvedArguments(true);
Argument arg = new Argument();
@ -535,8 +534,7 @@ public class CalculatedFieldTest extends AbstractContainerTest {
cf.setConfigurationVersion(1);
PropagationCalculatedFieldConfiguration cfg = new PropagationCalculatedFieldConfiguration();
cfg.setDirection(EntitySearchDirection.TO);
cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
cfg.setRelation(new RelationPathLevel(EntitySearchDirection.TO, EntityRelation.CONTAINS_TYPE));
cfg.setApplyExpressionToResolvedArguments(false); // arguments-only mode
Argument arg = new Argument();

5
ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules-table-config.ts

@ -54,6 +54,7 @@ import {
CalculatedFieldDebugDialogData
} from "@home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component";
import { AlarmSeverity, alarmSeverityTranslations } from "@shared/models/alarm.models";
import { UtilsService } from "@core/services/utils.service";
export class AlarmRulesTableConfig extends EntityTableConfig<any> {
@ -75,6 +76,7 @@ export class AlarmRulesTableConfig extends EntityTableConfig<any> {
private ownerId: EntityId = null,
private importExportService: ImportExportService,
private entityDebugSettingsService: EntityDebugSettingsService,
private utilsService: UtilsService,
) {
super();
this.tableTitle = this.translate.instant('alarm-rule.alarm-rules');
@ -115,7 +117,8 @@ export class AlarmRulesTableConfig extends EntityTableConfig<any> {
this.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.columns.push(new DateEntityTableColumn<CalculatedFieldAlarmRule>('createdTime', 'common.created-time', this.datePipe, '150px'));
this.columns.push(new EntityTableColumn<CalculatedFieldAlarmRule>('name', 'alarm-rule.alarm-type', '33%'));
this.columns.push(new EntityTableColumn<CalculatedFieldAlarmRule>('name', 'alarm-rule.alarm-type', '33%',
entity => this.utilsService.customTranslation(entity.name, entity.name)));
this.columns.push(new EntityTableColumn<CalculatedFieldAlarmRule>('createRule', 'alarm-rule.severities', '67%',
entity => Object.keys(entity.configuration.createRules).map((severity) => this.translate.instant(alarmSeverityTranslations.get(severity as AlarmSeverity))).join(', '),
() => ({}), false));

3
ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules-table.component.ts

@ -35,6 +35,7 @@ import { ImportExportService } from '@shared/import-export/import-export.service
import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service';
import { DatePipe } from '@angular/common';
import { AlarmRulesTableConfig } from "@home/components/alarm-rules/alarm-rules-table-config";
import { UtilsService } from "@core/services/utils.service";
@Component({
selector: 'tb-alarm-rules-table',
@ -63,6 +64,7 @@ export class AlarmRulesTableComponent {
private renderer: Renderer2,
private importExportService: ImportExportService,
private entityDebugSettingsService: EntityDebugSettingsService,
private utilsService: UtilsService,
private destroyRef: DestroyRef) {
effect(() => {
@ -80,6 +82,7 @@ export class AlarmRulesTableComponent {
this.ownerId(),
this.importExportService,
this.entityDebugSettingsService,
this.utilsService,
);
this.cd.markForCheck();
}

2
ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-schedule.component.html

@ -90,7 +90,7 @@
<input required matInput formControlName="endsOn" [matDatetimepicker]="endTimePicker">
</mat-form-field>
</div>
<div class="flex flex-1 items-center justify-center sm:max-w-[120px] mb-[22px] text-center"
<div class="flex flex-1 items-center justify-center sm:max-w-[120px] text-center"
[innerHTML]="getSchedulerRangeText(itemsSchedulerForm.at(day))">
</div>
</div>

1
ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.html

@ -35,6 +35,7 @@
</mat-form-field>
<tb-alarm-rule-filter-predicate-list [valueType]="data.valueType"
[arguments]="arguments"
[argumentInUse]="data.argumentInUse"
[operation]="complexFilterFormGroup.get('operation').value"
formControlName="predicates">
</tb-alarm-rule-filter-predicate-list>

1
ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.ts

@ -35,6 +35,7 @@ export interface AlarmRuleComplexFilterPredicateDialogData {
isAdd: boolean;
valueType: EntityKeyValueType;
arguments: Record<string, CalculatedFieldArgument>;
argumentInUse: string;
}
@Component({

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

@ -77,6 +77,7 @@
<tb-alarm-rule-filter-predicate-list [valueType]="filterFormGroup.get('valueType').value"
[operation]="filterFormGroup.get('operation').value"
[arguments]="arguments"
[argumentInUse]="filterFormGroup.get('argument').value"
formControlName="predicates">
</tb-alarm-rule-filter-predicate-list>
</section>

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

@ -42,6 +42,7 @@
<tb-alarm-rule-filter-predicate
class="flex-1"
[arguments]="arguments"
[argumentInUse]="argumentInUse"
[valueType]="valueType"
[formControl]="predicateControl">
</tb-alarm-rule-filter-predicate>

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

@ -78,6 +78,8 @@ export class AlarmRuleFilterPredicateListComponent implements ControlValueAccess
@Input() arguments: Record<string, CalculatedFieldArgument>;
@Input() argumentInUse: string;
filterListFormGroup = this.fb.group({
predicates: this.fb.array([])
});
@ -195,6 +197,7 @@ export class AlarmRuleFilterPredicateListComponent implements ControlValueAccess
valueType: this.valueType,
isAdd: true,
arguments: this.arguments,
argumentInUse: this.argumentInUse
}
}).afterClosed().pipe(
map(result => result)

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

@ -55,7 +55,7 @@
<mat-form-field class="flex-1 w-full" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="dynamicValueArgument" placeholder="{{ 'action.set' | translate }}">
@for (argument of argumentsList; track argument) {
<mat-option [value]="argument">{{ argument }}</mat-option>
<mat-option [value]="argument" [disabled]="argument === argumentInUse">{{ argument }}</mat-option>
}
</mat-select>
@if (filterPredicateValueFormGroup.get('dynamicValueArgument').touched && filterPredicateValueFormGroup.get('dynamicValueArgument').hasError('required')) {

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

@ -57,6 +57,9 @@ export class AlarmRuleFilterPredicateValueComponent implements ControlValueAcces
@Input()
valueType: EntityKeyValueType;
@Input()
argumentInUse: string;
valueTypeEnum = EntityKeyValueType;
filterPredicateValueFormGroup: FormGroup<FormControlsFrom<AlarmRuleValue<string | number | boolean>>>;
@ -104,7 +107,7 @@ export class AlarmRuleFilterPredicateValueComponent implements ControlValueAcces
});
this.dynamicModeControl.valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(value => this.updateValueModeValidators(value))
).subscribe(value => this.updateValueModeValidators(value));
}
setDisabledState(isDisabled: boolean): void {
@ -114,16 +117,17 @@ export class AlarmRuleFilterPredicateValueComponent implements ControlValueAcces
} else {
this.filterPredicateValueFormGroup.enable({emitEvent: false});
this.dynamicModeControl.enable({emitEvent: false});
this.updateValueModeValidators(this.dynamicModeControl.value);
}
}
private updateValueModeValidators(isDynamicMode: boolean): void {
if (isDynamicMode) {
this.filterPredicateValueFormGroup.get('staticValue').disable({emitEvent: false});
this.filterPredicateValueFormGroup.get('dynamicValueArgument').enable({emitEvent: false});
this.filterPredicateValueFormGroup.get('dynamicValueArgument').enable();
} else {
this.filterPredicateValueFormGroup.get('staticValue').enable({emitEvent: false});
this.filterPredicateValueFormGroup.get('dynamicValueArgument').disable({emitEvent: false});
this.filterPredicateValueFormGroup.get('staticValue').enable();
}
}
@ -142,7 +146,7 @@ export class AlarmRuleFilterPredicateValueComponent implements ControlValueAcces
writeValue(predicateValue: AlarmRuleValue<string | number | boolean>): void {
this.filterPredicateValueFormGroup.patchValue(predicateValue, {emitEvent: false});
this.dynamicModeControl.patchValue(!!predicateValue.dynamicValueArgument?.length);
this.dynamicModeControl.patchValue(!!predicateValue.dynamicValueArgument?.length, {emitEvent: false});
}
private updateModel() {

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

@ -71,6 +71,7 @@
@if (type !== filterPredicateType.COMPLEX) {
<tb-alarm-rule-filter-predicate-value class="flex-full"
[arguments]="arguments"
[argumentInUse]="argumentInUse"
[valueType]="valueType"
formControlName="value">
</tb-alarm-rule-filter-predicate-value>

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

@ -70,6 +70,9 @@ export class AlarmRuleFilterPredicateComponent implements ControlValueAccessor,
@Input()
arguments: Record<string, CalculatedFieldArgument>;
@Input()
argumentInUse: string;
filterPredicateFormGroup = this.fb.group({
operation: [],
ignoreCase: false,
@ -146,6 +149,7 @@ export class AlarmRuleFilterPredicateComponent implements ControlValueAccessor,
valueType: this.valueType,
isAdd: false,
arguments: this.arguments,
argumentInUse: this.argumentInUse,
}
}).afterClosed().subscribe(
(result) => {

5
ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts

@ -59,6 +59,7 @@ import { ImportExportService } from '@shared/import-export/import-export.service
import { isObject } from '@core/utils';
import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service';
import { DatePipe } from '@angular/common';
import { UtilsService } from "@core/services/utils.service";
export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedField> {
@ -80,6 +81,7 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
private ownerId: EntityId = null,
private importExportService: ImportExportService,
private entityDebugSettingsService: EntityDebugSettingsService,
private utilsService: UtilsService,
) {
super();
this.tableTitle = this.translate.instant('entity.type-calculated-fields');
@ -124,7 +126,8 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig<CalculatedFie
};
this.columns.push(new DateEntityTableColumn<CalculatedField>('createdTime', 'common.created-time', this.datePipe, '150px'));
this.columns.push(new EntityTableColumn<CalculatedField>('name', 'common.name', '33%'));
this.columns.push(new EntityTableColumn<CalculatedField>('name', 'common.name', '33%',
entity => this.utilsService.customTranslation(entity.name, entity.name)));
this.columns.push(new EntityTableColumn<CalculatedField>('type', 'common.type', '170px', entity => this.translate.instant(CalculatedFieldTypeTranslations.get(entity.type).name), () => ({whiteSpace: 'nowrap' })));
this.columns.push(expressionColumn);

3
ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts

@ -35,6 +35,7 @@ import { CalculatedFieldsService } from '@core/http/calculated-fields.service';
import { ImportExportService } from '@shared/import-export/import-export.service';
import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service';
import { DatePipe } from '@angular/common';
import { UtilsService } from "@core/services/utils.service";
@Component({
selector: 'tb-calculated-fields-table',
@ -63,6 +64,7 @@ export class CalculatedFieldsTableComponent {
private renderer: Renderer2,
private importExportService: ImportExportService,
private entityDebugSettingsService: EntityDebugSettingsService,
private utilsService: UtilsService,
private destroyRef: DestroyRef) {
effect(() => {
@ -80,6 +82,7 @@ export class CalculatedFieldsTableComponent {
this.ownerId(),
this.importExportService,
this.entityDebugSettingsService,
this.utilsService,
);
this.cd.markForCheck();
}

2
ui-ngx/src/assets/help/en_US/notification/alarm.md

@ -16,11 +16,13 @@ Available template parameters:
* `alarmStatus` - the alarm status;
* `alarmOriginatorEntityType` - the entity type of the alarm originator, e.g. 'Device';
* `alarmOriginatorName` - the name of the alarm originator, e.g. 'Sensor T1';
* `alarmOriginatorLabel` - the label of the alarm originator, e.g. 'Sensor T1';
* `alarmOriginatorId` - the alarm originator entity id as uuid string;
* `recipientTitle` - title of the recipient (first and last name if specified, email otherwise);
* `recipientEmail` - email of the recipient;
* `recipientFirstName` - first name of the recipient;
* `recipientLastName` - last name of the recipient;
* `details.<key>` - any key field from the alarm's details. Fox example, if details are `{"data": "Temperature is 25"}`, use `${details.data}` to access "Temperature is 25";
Parameter names must be wrapped using `${...}`. For example: `${action}`.
You may also modify the value of the parameter with one of the suffixes:

1
ui-ngx/src/assets/help/en_US/notification/alarm_assignment.md

@ -15,6 +15,7 @@ Available template parameters:
* `alarmStatus` - the alarm status;
* `alarmOriginatorEntityType` - the entity type of the alarm originator, e.g. 'Device';
* `alarmOriginatorName` - the name of the alarm originator, e.g. 'Sensor T1';
* `alarmOriginatorLabel` - the label of the alarm originator, e.g. 'Sensor T1';
* `alarmOriginatorId` - the alarm originator entity id as uuid string;
* `assigneeTitle` - title of the assignee;
* `assigneeEmail` - email of the assignee;

1
ui-ngx/src/assets/help/en_US/notification/alarm_comment.md

@ -15,6 +15,7 @@ Available template parameters:
* `alarmStatus` - the alarm status;
* `alarmOriginatorEntityType` - the entity type of the alarm originator, e.g. 'Device';
* `alarmOriginatorName` - the name of the alarm originator, e.g. 'Sensor T1';
* `alarmOriginatorLabel` - the label of the alarm originator, e.g. 'Sensor T1';
* `alarmOriginatorId` - the alarm originator entity id as uuid string;
* `comment` - text of the comment;
* `action` - one of: 'added', 'updated';

3
ui-ngx/src/assets/help/en_US/notification/edge_communication_failure.md

@ -12,6 +12,9 @@ Available template parameters:
* `edgeId` - the edge id as uuid string;
* `edgeName` - the name of the edge;
* `failureMsg` - the string representation of the failure, occurred on the Edge;
* `recipientEmail` - email of the recipient;
* `recipientFirstName` - first name of the recipient;
* `recipientLastName` - last name of the recipient;
Parameter names must be wrapped using `${...}`. For example: `${edgeName}`.
You may also modify the value of the parameter with one of the suffixes:

3
ui-ngx/src/assets/help/en_US/notification/edge_connection.md

@ -12,6 +12,9 @@ Available template parameters:
* `edgeId` - the edge id as uuid string;
* `edgeName` - the name of the edge;
* `eventType` - the string representation of the connectivity status: connected or disconnected;
* `recipientEmail` - email of the recipient;
* `recipientFirstName` - first name of the recipient;
* `recipientLastName` - last name of the recipient;
Parameter names must be wrapped using `${...}`. For example: `${edgeName}`.
You may also modify the value of the parameter with one of the suffixes:

3
ui-ngx/src/assets/help/en_US/notification/resources_shortage.md

@ -13,6 +13,9 @@ Available template parameters:
* `usage` - the current usage value of the resource;
* `serviceId` - the service id (convenient in cluster setup);
* `serviceType` - the service type (convenient in cluster setup);
* `recipientEmail` - email of the recipient;
* `recipientFirstName` - first name of the recipient;
* `recipientLastName` - last name of the recipient;
Parameter names must be wrapped using `${...}`. For example: `${resource}`.
You may also modify the value of the parameter with one of the suffixes:

3
ui-ngx/src/assets/help/en_US/notification/task_processing_failure.md

@ -16,6 +16,9 @@ Available template parameters:
* `entityType` - the type of the entity to which the task is related;
* `entityId` - the id of the entity to which the task is related;
* `attempt` - the number of attempts processing the task
* `recipientEmail` - email of the recipient;
* `recipientFirstName` - first name of the recipient;
* `recipientLastName` - last name of the recipient;
Parameter names must be wrapped using `${...}`. For example: `${entityType}`.
You may also modify the value of the parameter with one of the suffixes:

Loading…
Cancel
Save