Commit 5cc3a93cb9b45fd3c65fd7eec1aab1586bdd3194

Authored by Igor Kulikov
1 parent 6a237b84

Introduce default dashboard for device profile

Showing 21 changed files with 108 additions and 12 deletions
@@ -84,7 +84,8 @@ ALTER TABLE dashboard @@ -84,7 +84,8 @@ ALTER TABLE dashboard
84 ALTER TABLE device_profile 84 ALTER TABLE device_profile
85 ADD COLUMN IF NOT EXISTS image varchar(1000000), 85 ADD COLUMN IF NOT EXISTS image varchar(1000000),
86 ADD COLUMN IF NOT EXISTS firmware_id uuid, 86 ADD COLUMN IF NOT EXISTS firmware_id uuid,
87 - ADD COLUMN IF NOT EXISTS software_id uuid; 87 + ADD COLUMN IF NOT EXISTS software_id uuid,
  88 + ADD COLUMN IF NOT EXISTS default_dashboard_id uuid;
88 89
89 ALTER TABLE device 90 ALTER TABLE device
90 ADD COLUMN IF NOT EXISTS firmware_id uuid, 91 ADD COLUMN IF NOT EXISTS firmware_id uuid,
@@ -109,6 +110,12 @@ DO $$ @@ -109,6 +110,12 @@ DO $$
109 FOREIGN KEY (firmware_id) REFERENCES firmware(id); 110 FOREIGN KEY (firmware_id) REFERENCES firmware(id);
110 END IF; 111 END IF;
111 112
  113 + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_dashboard_device_profile') THEN
  114 + ALTER TABLE device_profile
  115 + ADD CONSTRAINT fk_default_dashboard_device_profile
  116 + FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id);
  117 + END IF;
  118 +
112 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN 119 IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN
113 ALTER TABLE device 120 ALTER TABLE device
114 ADD CONSTRAINT fk_firmware_device 121 ADD CONSTRAINT fk_firmware_device
@@ -313,7 +313,8 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -313,7 +313,8 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
313 Collections.sort(loadedDeviceProfileInfos, deviceProfileInfoIdComparator); 313 Collections.sort(loadedDeviceProfileInfos, deviceProfileInfoIdComparator);
314 314
315 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream().map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(), 315 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream().map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(),
316 - deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); 316 + deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getDefaultDashboardId(),
  317 + deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList());
317 318
318 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos); 319 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos);
319 320
@@ -21,6 +21,7 @@ import lombok.Data; @@ -21,6 +21,7 @@ import lombok.Data;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
22 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 23 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  24 +import org.thingsboard.server.common.data.id.DashboardId;
24 import org.thingsboard.server.common.data.id.DeviceProfileId; 25 import org.thingsboard.server.common.data.id.DeviceProfileId;
25 import org.thingsboard.server.common.data.id.FirmwareId; 26 import org.thingsboard.server.common.data.id.FirmwareId;
26 import org.thingsboard.server.common.data.id.RuleChainId; 27 import org.thingsboard.server.common.data.id.RuleChainId;
@@ -49,6 +50,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -49,6 +50,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
49 private DeviceTransportType transportType; 50 private DeviceTransportType transportType;
50 private DeviceProfileProvisionType provisionType; 51 private DeviceProfileProvisionType provisionType;
51 private RuleChainId defaultRuleChainId; 52 private RuleChainId defaultRuleChainId;
  53 + private DashboardId defaultDashboardId;
52 @NoXss 54 @NoXss
53 private String defaultQueueName; 55 private String defaultQueueName;
54 @Valid 56 @Valid
@@ -78,6 +80,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H @@ -78,6 +80,7 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
78 this.image = deviceProfile.getImage(); 80 this.image = deviceProfile.getImage();
79 this.isDefault = deviceProfile.isDefault(); 81 this.isDefault = deviceProfile.isDefault();
80 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId(); 82 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId();
  83 + this.defaultDashboardId = deviceProfile.getDefaultDashboardId();
81 this.defaultQueueName = deviceProfile.getDefaultQueueName(); 84 this.defaultQueueName = deviceProfile.getDefaultQueueName();
82 this.setProfileData(deviceProfile.getProfileData()); 85 this.setProfileData(deviceProfile.getProfileData());
83 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); 86 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
20 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
21 import lombok.ToString; 21 import lombok.ToString;
22 import lombok.Value; 22 import lombok.Value;
  23 +import org.thingsboard.server.common.data.id.DashboardId;
23 import org.thingsboard.server.common.data.id.EntityId; 24 import org.thingsboard.server.common.data.id.EntityId;
24 import org.thingsboard.server.common.data.id.EntityIdFactory; 25 import org.thingsboard.server.common.data.id.EntityIdFactory;
25 26
@@ -31,6 +32,7 @@ import java.util.UUID; @@ -31,6 +32,7 @@ import java.util.UUID;
31 public class DeviceProfileInfo extends EntityInfo { 32 public class DeviceProfileInfo extends EntityInfo {
32 33
33 private final String image; 34 private final String image;
  35 + private final DashboardId defaultDashboardId;
34 private final DeviceProfileType type; 36 private final DeviceProfileType type;
35 private final DeviceTransportType transportType; 37 private final DeviceTransportType transportType;
36 38
@@ -38,17 +40,20 @@ public class DeviceProfileInfo extends EntityInfo { @@ -38,17 +40,20 @@ public class DeviceProfileInfo extends EntityInfo {
38 public DeviceProfileInfo(@JsonProperty("id") EntityId id, 40 public DeviceProfileInfo(@JsonProperty("id") EntityId id,
39 @JsonProperty("name") String name, 41 @JsonProperty("name") String name,
40 @JsonProperty("image") String image, 42 @JsonProperty("image") String image,
  43 + @JsonProperty("defaultDashboardId") DashboardId defaultDashboardId,
41 @JsonProperty("type") DeviceProfileType type, 44 @JsonProperty("type") DeviceProfileType type,
42 @JsonProperty("transportType") DeviceTransportType transportType) { 45 @JsonProperty("transportType") DeviceTransportType transportType) {
43 super(id, name); 46 super(id, name);
44 this.image = image; 47 this.image = image;
  48 + this.defaultDashboardId = defaultDashboardId;
45 this.type = type; 49 this.type = type;
46 this.transportType = transportType; 50 this.transportType = transportType;
47 } 51 }
48 52
49 - public DeviceProfileInfo(UUID uuid, String name, String image, DeviceProfileType type, DeviceTransportType transportType) { 53 + public DeviceProfileInfo(UUID uuid, String name, String image, UUID defaultDashboardId, DeviceProfileType type, DeviceTransportType transportType) {
50 super(EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE_PROFILE, uuid), name); 54 super(EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE_PROFILE, uuid), name);
51 this.image = image; 55 this.image = image;
  56 + this.defaultDashboardId = defaultDashboardId != null ? new DashboardId(defaultDashboardId) : null;
52 this.type = type; 57 this.type = type;
53 this.transportType = transportType; 58 this.transportType = transportType;
54 } 59 }
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.dashboard; @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.dashboard;
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.apache.commons.lang3.StringUtils; 20 import org.apache.commons.lang3.StringUtils;
  21 +import org.hibernate.exception.ConstraintViolationException;
21 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.context.annotation.Lazy; 23 import org.springframework.context.annotation.Lazy;
23 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
@@ -166,7 +167,16 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb @@ -166,7 +167,16 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
166 log.trace("Executing deleteDashboard [{}]", dashboardId); 167 log.trace("Executing deleteDashboard [{}]", dashboardId);
167 Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId); 168 Validator.validateId(dashboardId, INCORRECT_DASHBOARD_ID + dashboardId);
168 deleteEntityRelations(tenantId, dashboardId); 169 deleteEntityRelations(tenantId, dashboardId);
169 - dashboardDao.removeById(tenantId, dashboardId.getId()); 170 + try {
  171 + dashboardDao.removeById(tenantId, dashboardId.getId());
  172 + } catch (Exception t) {
  173 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  174 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_dashboard_device_profile")) {
  175 + throw new DataValidationException("The dashboard referenced by the device profiles cannot be deleted!");
  176 + } else {
  177 + throw t;
  178 + }
  179 + }
170 } 180 }
171 181
172 @Override 182 @Override
@@ -36,6 +36,7 @@ import org.springframework.cache.CacheManager; @@ -36,6 +36,7 @@ import org.springframework.cache.CacheManager;
36 import org.springframework.cache.annotation.Cacheable; 36 import org.springframework.cache.annotation.Cacheable;
37 import org.springframework.stereotype.Service; 37 import org.springframework.stereotype.Service;
38 import org.springframework.util.CollectionUtils; 38 import org.springframework.util.CollectionUtils;
  39 +import org.thingsboard.server.common.data.DashboardInfo;
39 import org.thingsboard.server.common.data.Device; 40 import org.thingsboard.server.common.data.Device;
40 import org.thingsboard.server.common.data.DeviceProfile; 41 import org.thingsboard.server.common.data.DeviceProfile;
41 import org.thingsboard.server.common.data.DeviceProfileInfo; 42 import org.thingsboard.server.common.data.DeviceProfileInfo;
@@ -61,9 +62,12 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -61,9 +62,12 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
61 import org.thingsboard.server.common.data.id.TenantId; 62 import org.thingsboard.server.common.data.id.TenantId;
62 import org.thingsboard.server.common.data.page.PageData; 63 import org.thingsboard.server.common.data.page.PageData;
63 import org.thingsboard.server.common.data.page.PageLink; 64 import org.thingsboard.server.common.data.page.PageLink;
  65 +import org.thingsboard.server.common.data.rule.RuleChain;
  66 +import org.thingsboard.server.dao.dashboard.DashboardService;
64 import org.thingsboard.server.dao.entity.AbstractEntityService; 67 import org.thingsboard.server.dao.entity.AbstractEntityService;
65 import org.thingsboard.server.dao.exception.DataValidationException; 68 import org.thingsboard.server.dao.exception.DataValidationException;
66 import org.thingsboard.server.dao.firmware.FirmwareService; 69 import org.thingsboard.server.dao.firmware.FirmwareService;
  70 +import org.thingsboard.server.dao.rule.RuleChainService;
67 import org.thingsboard.server.dao.service.DataValidator; 71 import org.thingsboard.server.dao.service.DataValidator;
68 import org.thingsboard.server.dao.service.PaginatedRemover; 72 import org.thingsboard.server.dao.service.PaginatedRemover;
69 import org.thingsboard.server.dao.service.Validator; 73 import org.thingsboard.server.dao.service.Validator;
@@ -117,6 +121,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -117,6 +121,12 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
117 @Autowired 121 @Autowired
118 private FirmwareService firmwareService; 122 private FirmwareService firmwareService;
119 123
  124 + @Autowired
  125 + private RuleChainService ruleChainService;
  126 +
  127 + @Autowired
  128 + private DashboardService dashboardService;
  129 +
120 private final Lock findOrCreateLock = new ReentrantLock(); 130 private final Lock findOrCreateLock = new ReentrantLock();
121 131
122 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") 132 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}")
@@ -336,7 +346,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -336,7 +346,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
336 } 346 }
337 347
338 private DataValidator<DeviceProfile> deviceProfileValidator = 348 private DataValidator<DeviceProfile> deviceProfileValidator =
339 - new DataValidator<DeviceProfile>() { 349 + new DataValidator<>() {
340 @Override 350 @Override
341 protected void validateDataImpl(TenantId tenantId, DeviceProfile deviceProfile) { 351 protected void validateDataImpl(TenantId tenantId, DeviceProfile deviceProfile) {
342 if (StringUtils.isEmpty(deviceProfile.getName())) { 352 if (StringUtils.isEmpty(deviceProfile.getName())) {
@@ -402,6 +412,20 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -402,6 +412,20 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
402 } 412 }
403 } 413 }
404 414
  415 + if (deviceProfile.getDefaultRuleChainId() != null) {
  416 + RuleChain ruleChain = ruleChainService.findRuleChainById(tenantId, deviceProfile.getDefaultRuleChainId());
  417 + if (ruleChain == null) {
  418 + throw new DataValidationException("Can't assign non-existent rule chain!");
  419 + }
  420 + }
  421 +
  422 + if (deviceProfile.getDefaultDashboardId() != null) {
  423 + DashboardInfo dashboard = dashboardService.findDashboardInfoById(tenantId, deviceProfile.getDefaultDashboardId());
  424 + if (dashboard == null) {
  425 + throw new DataValidationException("Can't assign non-existent dashboard!");
  426 + }
  427 + }
  428 +
405 if (deviceProfile.getFirmwareId() != null) { 429 if (deviceProfile.getFirmwareId() != null) {
406 Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId()); 430 Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId());
407 if (firmware == null) { 431 if (firmware == null) {
@@ -177,6 +177,7 @@ public class ModelConstants { @@ -177,6 +177,7 @@ public class ModelConstants {
177 public static final String DEVICE_PROFILE_DESCRIPTION_PROPERTY = "description"; 177 public static final String DEVICE_PROFILE_DESCRIPTION_PROPERTY = "description";
178 public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default"; 178 public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default";
179 public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id"; 179 public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id";
  180 + public static final String DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY = "default_dashboard_id";
180 public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name"; 181 public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name";
181 public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key"; 182 public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key";
182 public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id"; 183 public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id";
@@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType;
27 import org.thingsboard.server.common.data.DeviceProfileType; 27 import org.thingsboard.server.common.data.DeviceProfileType;
28 import org.thingsboard.server.common.data.DeviceTransportType; 28 import org.thingsboard.server.common.data.DeviceTransportType;
29 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 29 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  30 +import org.thingsboard.server.common.data.id.DashboardId;
30 import org.thingsboard.server.common.data.id.DeviceProfileId; 31 import org.thingsboard.server.common.data.id.DeviceProfileId;
31 import org.thingsboard.server.common.data.id.FirmwareId; 32 import org.thingsboard.server.common.data.id.FirmwareId;
32 import org.thingsboard.server.common.data.id.RuleChainId; 33 import org.thingsboard.server.common.data.id.RuleChainId;
@@ -83,6 +84,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -83,6 +84,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
83 @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY, columnDefinition = "uuid") 84 @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY, columnDefinition = "uuid")
84 private UUID defaultRuleChainId; 85 private UUID defaultRuleChainId;
85 86
  87 + @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY)
  88 + private UUID defaultDashboardId;
  89 +
86 @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY) 90 @Column(name = ModelConstants.DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY)
87 private String defaultQueueName; 91 private String defaultQueueName;
88 92
@@ -122,6 +126,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -122,6 +126,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
122 if (deviceProfile.getDefaultRuleChainId() != null) { 126 if (deviceProfile.getDefaultRuleChainId() != null) {
123 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId().getId(); 127 this.defaultRuleChainId = deviceProfile.getDefaultRuleChainId().getId();
124 } 128 }
  129 + if (deviceProfile.getDefaultDashboardId() != null) {
  130 + this.defaultDashboardId = deviceProfile.getDefaultDashboardId().getId();
  131 + }
125 this.defaultQueueName = deviceProfile.getDefaultQueueName(); 132 this.defaultQueueName = deviceProfile.getDefaultQueueName();
126 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); 133 this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey();
127 if (deviceProfile.getFirmwareId() != null) { 134 if (deviceProfile.getFirmwareId() != null) {
@@ -164,6 +171,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl @@ -164,6 +171,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
164 if (defaultRuleChainId != null) { 171 if (defaultRuleChainId != null) {
165 deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId)); 172 deviceProfile.setDefaultRuleChainId(new RuleChainId(defaultRuleChainId));
166 } 173 }
  174 + if (defaultDashboardId != null) {
  175 + deviceProfile.setDefaultDashboardId(new DashboardId(defaultDashboardId));
  176 + }
167 deviceProfile.setDefaultQueueName(defaultQueueName); 177 deviceProfile.setDefaultQueueName(defaultQueueName);
168 deviceProfile.setProvisionDeviceKey(provisionDeviceKey); 178 deviceProfile.setProvisionDeviceKey(provisionDeviceKey);
169 179
@@ -28,7 +28,7 @@ import java.util.UUID; @@ -28,7 +28,7 @@ import java.util.UUID;
28 28
29 public interface DeviceProfileRepository extends PagingAndSortingRepository<DeviceProfileEntity, UUID> { 29 public interface DeviceProfileRepository extends PagingAndSortingRepository<DeviceProfileEntity, UUID> {
30 30
31 - @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.type, d.transportType) " + 31 + @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " +
32 "FROM DeviceProfileEntity d " + 32 "FROM DeviceProfileEntity d " +
33 "WHERE d.id = :deviceProfileId") 33 "WHERE d.id = :deviceProfileId")
34 DeviceProfileInfo findDeviceProfileInfoById(@Param("deviceProfileId") UUID deviceProfileId); 34 DeviceProfileInfo findDeviceProfileInfoById(@Param("deviceProfileId") UUID deviceProfileId);
@@ -39,14 +39,14 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi @@ -39,14 +39,14 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi
39 @Param("textSearch") String textSearch, 39 @Param("textSearch") String textSearch,
40 Pageable pageable); 40 Pageable pageable);
41 41
42 - @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.type, d.transportType) " + 42 + @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " +
43 "FROM DeviceProfileEntity d WHERE " + 43 "FROM DeviceProfileEntity d WHERE " +
44 "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") 44 "d.tenantId = :tenantId AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
45 Page<DeviceProfileInfo> findDeviceProfileInfos(@Param("tenantId") UUID tenantId, 45 Page<DeviceProfileInfo> findDeviceProfileInfos(@Param("tenantId") UUID tenantId,
46 @Param("textSearch") String textSearch, 46 @Param("textSearch") String textSearch,
47 Pageable pageable); 47 Pageable pageable);
48 48
49 - @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.type, d.transportType) " + 49 + @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " +
50 "FROM DeviceProfileEntity d WHERE " + 50 "FROM DeviceProfileEntity d WHERE " +
51 "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))") 51 "d.tenantId = :tenantId AND d.transportType = :transportType AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
52 Page<DeviceProfileInfo> findDeviceProfileInfos(@Param("tenantId") UUID tenantId, 52 Page<DeviceProfileInfo> findDeviceProfileInfos(@Param("tenantId") UUID tenantId,
@@ -58,7 +58,7 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi @@ -58,7 +58,7 @@ public interface DeviceProfileRepository extends PagingAndSortingRepository<Devi
58 "WHERE d.tenantId = :tenantId AND d.isDefault = true") 58 "WHERE d.tenantId = :tenantId AND d.isDefault = true")
59 DeviceProfileEntity findByDefaultTrueAndTenantId(@Param("tenantId") UUID tenantId); 59 DeviceProfileEntity findByDefaultTrueAndTenantId(@Param("tenantId") UUID tenantId);
60 60
61 - @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.type, d.transportType) " + 61 + @Query("SELECT new org.thingsboard.server.common.data.DeviceProfileInfo(d.id, d.name, d.image, d.defaultDashboardId, d.type, d.transportType) " +
62 "FROM DeviceProfileEntity d " + 62 "FROM DeviceProfileEntity d " +
63 "WHERE d.tenantId = :tenantId AND d.isDefault = true") 63 "WHERE d.tenantId = :tenantId AND d.isDefault = true")
64 DeviceProfileInfo findDefaultDeviceProfileInfo(@Param("tenantId") UUID tenantId); 64 DeviceProfileInfo findDefaultDeviceProfileInfo(@Param("tenantId") UUID tenantId);
@@ -87,7 +87,9 @@ public class AlarmDataAdapter { @@ -87,7 +87,9 @@ public class AlarmDataAdapter {
87 alarm.setSeverity(AlarmSeverity.valueOf(row.get(ModelConstants.ALARM_SEVERITY_PROPERTY).toString())); 87 alarm.setSeverity(AlarmSeverity.valueOf(row.get(ModelConstants.ALARM_SEVERITY_PROPERTY).toString()));
88 alarm.setStatus(AlarmStatus.valueOf(row.get(ModelConstants.ALARM_STATUS_PROPERTY).toString())); 88 alarm.setStatus(AlarmStatus.valueOf(row.get(ModelConstants.ALARM_STATUS_PROPERTY).toString()));
89 alarm.setTenantId(new TenantId((UUID) row.get(ModelConstants.TENANT_ID_PROPERTY))); 89 alarm.setTenantId(new TenantId((UUID) row.get(ModelConstants.TENANT_ID_PROPERTY)));
90 - alarm.setCustomerId(new CustomerId((UUID) row.get(ModelConstants.CUSTOMER_ID_PROPERTY))); 90 + Object customerIdObj = row.get(ModelConstants.CUSTOMER_ID_PROPERTY);
  91 + CustomerId customerId = customerIdObj != null ? new CustomerId((UUID) customerIdObj) : null;
  92 + alarm.setCustomerId(customerId);
91 if (row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES) != null) { 93 if (row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES) != null) {
92 String propagateRelationTypes = row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES).toString(); 94 String propagateRelationTypes = row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES).toString();
93 if (!StringUtils.isEmpty(propagateRelationTypes)) { 95 if (!StringUtils.isEmpty(propagateRelationTypes)) {
@@ -140,11 +140,11 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -140,11 +140,11 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
140 Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 140 Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
141 customerService.deleteCustomersByTenantId(tenantId); 141 customerService.deleteCustomersByTenantId(tenantId);
142 widgetsBundleService.deleteWidgetsBundlesByTenantId(tenantId); 142 widgetsBundleService.deleteWidgetsBundlesByTenantId(tenantId);
143 - dashboardService.deleteDashboardsByTenantId(tenantId);  
144 entityViewService.deleteEntityViewsByTenantId(tenantId); 143 entityViewService.deleteEntityViewsByTenantId(tenantId);
145 assetService.deleteAssetsByTenantId(tenantId); 144 assetService.deleteAssetsByTenantId(tenantId);
146 deviceService.deleteDevicesByTenantId(tenantId); 145 deviceService.deleteDevicesByTenantId(tenantId);
147 deviceProfileService.deleteDeviceProfilesByTenantId(tenantId); 146 deviceProfileService.deleteDeviceProfilesByTenantId(tenantId);
  147 + dashboardService.deleteDashboardsByTenantId(tenantId);
148 edgeService.deleteEdgesByTenantId(tenantId); 148 edgeService.deleteEdgesByTenantId(tenantId);
149 userService.deleteTenantAdmins(tenantId); 149 userService.deleteTenantAdmins(tenantId);
150 ruleChainService.deleteRuleChainsByTenantId(tenantId); 150 ruleChainService.deleteRuleChainsByTenantId(tenantId);
@@ -195,11 +195,13 @@ CREATE TABLE IF NOT EXISTS device_profile ( @@ -195,11 +195,13 @@ CREATE TABLE IF NOT EXISTS device_profile (
195 firmware_id uuid, 195 firmware_id uuid,
196 software_id uuid, 196 software_id uuid,
197 default_rule_chain_id uuid, 197 default_rule_chain_id uuid,
  198 + default_dashboard_id uuid,
198 default_queue_name varchar(255), 199 default_queue_name varchar(255),
199 provision_device_key varchar, 200 provision_device_key varchar,
200 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 201 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name),
201 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), 202 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
202 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), 203 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
  204 + CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id),
203 CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id), 205 CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id),
204 CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id) 206 CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id)
205 ); 207 );
@@ -214,11 +214,13 @@ CREATE TABLE IF NOT EXISTS device_profile ( @@ -214,11 +214,13 @@ CREATE TABLE IF NOT EXISTS device_profile (
214 firmware_id uuid, 214 firmware_id uuid,
215 software_id uuid, 215 software_id uuid,
216 default_rule_chain_id uuid, 216 default_rule_chain_id uuid,
  217 + default_dashboard_id uuid,
217 default_queue_name varchar(255), 218 default_queue_name varchar(255),
218 provision_device_key varchar, 219 provision_device_key varchar,
219 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 220 CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name),
220 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key), 221 CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
221 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id), 222 CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
  223 + CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id),
222 CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id), 224 CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id),
223 CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id) 225 CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id)
224 ); 226 );
@@ -333,7 +333,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -333,7 +333,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
333 333
334 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream() 334 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream()
335 .map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(), 335 .map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(),
336 - deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); 336 + deviceProfile.getName(), deviceProfile.getImage(), deviceProfile.getDefaultDashboardId(),
  337 + deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList());
337 338
338 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos); 339 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos);
339 340
@@ -45,6 +45,10 @@ @@ -45,6 +45,10 @@
45 labelText="device-profile.default-rule-chain" 45 labelText="device-profile.default-rule-chain"
46 formControlName="defaultRuleChainId"> 46 formControlName="defaultRuleChainId">
47 </tb-rule-chain-autocomplete> 47 </tb-rule-chain-autocomplete>
  48 + <tb-dashboard-autocomplete
  49 + placeholder="{{'device-profile.default-dashboard' | translate}}"
  50 + formControlName="defaultDashboardId">
  51 + </tb-dashboard-autocomplete>
48 <tb-queue-type-list 52 <tb-queue-type-list
49 [queueType]="serviceType" 53 [queueType]="serviceType"
50 formControlName="defaultQueueName"> 54 formControlName="defaultQueueName">
@@ -49,6 +49,7 @@ import { RuleChainId } from '@shared/models/id/rule-chain-id'; @@ -49,6 +49,7 @@ import { RuleChainId } from '@shared/models/id/rule-chain-id';
49 import { StepperSelectionEvent } from '@angular/cdk/stepper'; 49 import { StepperSelectionEvent } from '@angular/cdk/stepper';
50 import { deepTrim } from '@core/utils'; 50 import { deepTrim } from '@core/utils';
51 import { ServiceType } from '@shared/models/queue.models'; 51 import { ServiceType } from '@shared/models/queue.models';
  52 +import { DashboardId } from '@shared/models/id/dashboard-id';
52 53
53 export interface AddDeviceProfileDialogData { 54 export interface AddDeviceProfileDialogData {
54 deviceProfileName: string; 55 deviceProfileName: string;
@@ -108,6 +109,7 @@ export class AddDeviceProfileDialogComponent extends @@ -108,6 +109,7 @@ export class AddDeviceProfileDialogComponent extends
108 type: [DeviceProfileType.DEFAULT, [Validators.required]], 109 type: [DeviceProfileType.DEFAULT, [Validators.required]],
109 image: [null, []], 110 image: [null, []],
110 defaultRuleChainId: [null, []], 111 defaultRuleChainId: [null, []],
  112 + defaultDashboardId: [null, []],
111 defaultQueueName: ['', []], 113 defaultQueueName: ['', []],
112 description: ['', []] 114 description: ['', []]
113 } 115 }
@@ -199,6 +201,9 @@ export class AddDeviceProfileDialogComponent extends @@ -199,6 +201,9 @@ export class AddDeviceProfileDialogComponent extends
199 if (this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value) { 201 if (this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value) {
200 deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value); 202 deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value);
201 } 203 }
  204 + if (this.deviceProfileDetailsFormGroup.get('defaultDashboardId').value) {
  205 + deviceProfile.defaultDashboardId = new DashboardId(this.deviceProfileDetailsFormGroup.get('defaultDashboardId').value);
  206 + }
202 this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).subscribe( 207 this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).subscribe(
203 (savedDeviceProfile) => { 208 (savedDeviceProfile) => {
204 this.dialogRef.close(savedDeviceProfile); 209 this.dialogRef.close(savedDeviceProfile);
@@ -59,6 +59,10 @@ @@ -59,6 +59,10 @@
59 labelText="device-profile.default-rule-chain" 59 labelText="device-profile.default-rule-chain"
60 formControlName="defaultRuleChainId"> 60 formControlName="defaultRuleChainId">
61 </tb-rule-chain-autocomplete> 61 </tb-rule-chain-autocomplete>
  62 + <tb-dashboard-autocomplete
  63 + placeholder="{{'device-profile.default-dashboard' | translate}}"
  64 + formControlName="defaultDashboardId">
  65 + </tb-dashboard-autocomplete>
62 <tb-queue-type-list 66 <tb-queue-type-list
63 [queueType]="serviceType" 67 [queueType]="serviceType"
64 formControlName="defaultQueueName"> 68 formControlName="defaultQueueName">
@@ -41,6 +41,7 @@ import { RuleChainId } from '@shared/models/id/rule-chain-id'; @@ -41,6 +41,7 @@ import { RuleChainId } from '@shared/models/id/rule-chain-id';
41 import { ServiceType } from '@shared/models/queue.models'; 41 import { ServiceType } from '@shared/models/queue.models';
42 import { EntityId } from '@shared/models/id/entity-id'; 42 import { EntityId } from '@shared/models/id/entity-id';
43 import { FirmwareType } from '@shared/models/firmware.models'; 43 import { FirmwareType } from '@shared/models/firmware.models';
  44 +import { DashboardId } from '@shared/models/id/dashboard-id';
44 45
45 @Component({ 46 @Component({
46 selector: 'tb-device-profile', 47 selector: 'tb-device-profile',
@@ -112,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -112,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
112 provisionConfiguration: [deviceProvisionConfiguration, Validators.required] 113 provisionConfiguration: [deviceProvisionConfiguration, Validators.required]
113 }), 114 }),
114 defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], 115 defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []],
  116 + defaultDashboardId: [entity && entity.defaultDashboardId ? entity.defaultDashboardId.id : null, []],
115 defaultQueueName: [entity ? entity.defaultQueueName : '', []], 117 defaultQueueName: [entity ? entity.defaultQueueName : '', []],
116 firmwareId: [entity ? entity.firmwareId : null], 118 firmwareId: [entity ? entity.firmwareId : null],
117 softwareId: [entity ? entity.softwareId : null], 119 softwareId: [entity ? entity.softwareId : null],
@@ -190,6 +192,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -190,6 +192,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
190 provisionConfiguration: deviceProvisionConfiguration 192 provisionConfiguration: deviceProvisionConfiguration
191 }}, {emitEvent: false}); 193 }}, {emitEvent: false});
192 this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false}); 194 this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false});
  195 + this.entityForm.patchValue({defaultDashboardId: entity.defaultDashboardId ? entity.defaultDashboardId.id : null}, {emitEvent: false});
193 this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false}); 196 this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false});
194 this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); 197 this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false});
195 this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false}); 198 this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false});
@@ -200,6 +203,9 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { @@ -200,6 +203,9 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
200 if (formValue.defaultRuleChainId) { 203 if (formValue.defaultRuleChainId) {
201 formValue.defaultRuleChainId = new RuleChainId(formValue.defaultRuleChainId); 204 formValue.defaultRuleChainId = new RuleChainId(formValue.defaultRuleChainId);
202 } 205 }
  206 + if (formValue.defaultDashboardId) {
  207 + formValue.defaultDashboardId = new DashboardId(formValue.defaultDashboardId);
  208 + }
203 const deviceProvisionConfiguration: DeviceProvisionConfiguration = formValue.profileData.provisionConfiguration; 209 const deviceProvisionConfiguration: DeviceProvisionConfiguration = formValue.profileData.provisionConfiguration;
204 formValue.provisionType = deviceProvisionConfiguration.type; 210 formValue.provisionType = deviceProvisionConfiguration.type;
205 formValue.provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey; 211 formValue.provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey;
@@ -139,6 +139,11 @@ export class DashboardAutocompleteComponent implements ControlValueAccessor, OnI @@ -139,6 +139,11 @@ export class DashboardAutocompleteComponent implements ControlValueAccessor, OnI
139 139
140 setDisabledState(isDisabled: boolean): void { 140 setDisabledState(isDisabled: boolean): void {
141 this.disabled = isDisabled; 141 this.disabled = isDisabled;
  142 + if (this.disabled) {
  143 + this.selectDashboardFormGroup.disable({emitEvent: false});
  144 + } else {
  145 + this.selectDashboardFormGroup.enable({emitEvent: false});
  146 + }
142 } 147 }
143 148
144 writeValue(value: DashboardInfo | string | null): void { 149 writeValue(value: DashboardInfo | string | null): void {
@@ -28,6 +28,7 @@ import { TimeUnit } from '@shared/models/time/time.models'; @@ -28,6 +28,7 @@ import { TimeUnit } from '@shared/models/time/time.models';
28 import * as _moment from 'moment'; 28 import * as _moment from 'moment';
29 import { AbstractControl, ValidationErrors } from '@angular/forms'; 29 import { AbstractControl, ValidationErrors } from '@angular/forms';
30 import { FirmwareId } from '@shared/models/id/firmware-id'; 30 import { FirmwareId } from '@shared/models/id/firmware-id';
  31 +import { DashboardId } from '@shared/models/id/dashboard-id';
31 32
32 export enum DeviceProfileType { 33 export enum DeviceProfileType {
33 DEFAULT = 'DEFAULT', 34 DEFAULT = 'DEFAULT',
@@ -497,6 +498,7 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> { @@ -497,6 +498,7 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> {
497 provisionType: DeviceProvisionType; 498 provisionType: DeviceProvisionType;
498 provisionDeviceKey?: string; 499 provisionDeviceKey?: string;
499 defaultRuleChainId?: RuleChainId; 500 defaultRuleChainId?: RuleChainId;
  501 + defaultDashboardId?: DashboardId;
500 defaultQueueName?: string; 502 defaultQueueName?: string;
501 firmwareId?: FirmwareId; 503 firmwareId?: FirmwareId;
502 softwareId?: FirmwareId; 504 softwareId?: FirmwareId;
@@ -507,6 +509,7 @@ export interface DeviceProfileInfo extends EntityInfoData { @@ -507,6 +509,7 @@ export interface DeviceProfileInfo extends EntityInfoData {
507 type: DeviceProfileType; 509 type: DeviceProfileType;
508 transportType: DeviceTransportType; 510 transportType: DeviceTransportType;
509 image?: string; 511 image?: string;
  512 + defaultDashboardId?: DashboardId;
510 } 513 }
511 514
512 export interface DefaultDeviceConfiguration { 515 export interface DefaultDeviceConfiguration {
@@ -1048,6 +1048,7 @@ @@ -1048,6 +1048,7 @@
1048 "profile-configuration": "Profile configuration", 1048 "profile-configuration": "Profile configuration",
1049 "transport-configuration": "Transport configuration", 1049 "transport-configuration": "Transport configuration",
1050 "default-rule-chain": "Default rule chain", 1050 "default-rule-chain": "Default rule chain",
  1051 + "default-dashboard": "Default dashboard",
1051 "select-queue-hint": "Select from a drop-down list or add a custom name.", 1052 "select-queue-hint": "Select from a drop-down list or add a custom name.",
1052 "delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?", 1053 "delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?",
1053 "delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data will become unrecoverable.", 1054 "delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data will become unrecoverable.",