From 53d118dcf36f0f5a0e24e59001f6fc9ac1e1f6ec Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 15 Apr 2026 17:18:02 +0300 Subject: [PATCH] feat(solutions): add dashboard assignment to edge provisioning, minor style fix --- .../solutions/DefaultSolutionService.java | 58 ++++++++++++------- .../data/definition/EdgeDefinition.java | 1 + .../iot-hub-update-dialog.component.scss | 1 + 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/solutions/DefaultSolutionService.java b/application/src/main/java/org/thingsboard/server/service/solutions/DefaultSolutionService.java index b340702385..8000692f04 100644 --- a/application/src/main/java/org/thingsboard/server/service/solutions/DefaultSolutionService.java +++ b/application/src/main/java/org/thingsboard/server/service/solutions/DefaultSolutionService.java @@ -91,6 +91,7 @@ import org.thingsboard.server.service.entitiy.asset.TbAssetService; import org.thingsboard.server.service.entitiy.cf.TbCalculatedFieldService; import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService; +import org.thingsboard.server.service.entitiy.entity.relation.TbEntityRelationService; import org.thingsboard.server.service.rule.TbRuleChainService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.system.SystemSecurityService; @@ -177,7 +178,7 @@ public class DefaultSolutionService implements SolutionService { private final DashboardService dashboardService; private final EdgeService edgeService; private final TbEdgeService tbEdgeService; - private final RelationService relationService; + private final TbEntityRelationService relationService; private final AlarmService alarmService; private final CalculatedFieldService calculatedFieldService; private final TbCalculatedFieldService tbCalculatedFieldService; @@ -680,6 +681,7 @@ public class DefaultSolutionService implements SolutionService { assignRuleChainsToEdge(ctx, entityDef.getRuleChainIds(), entity); assignAssetsToEdge(ctx, entityDef.getAssetIds(), entity); assignDevicesToEdge(ctx, entityDef.getDeviceIds(), entity); + assignDashboardsToEdge(ctx, entityDef.getDashboardIds(), entity); log.info("[{}] Saved edge: {}", entity.getId(), entity); EdgeId entityId = entity.getId(); ctx.putIdToMap(entityDef, entityId); @@ -737,6 +739,22 @@ public class DefaultSolutionService implements SolutionService { } } + private void assignDashboardsToEdge(SolutionInstallContext ctx, List dashboardIds, Edge entity) { + if (dashboardIds == null || dashboardIds.isEmpty()) { + return; + } + for (String strDashboardId : dashboardIds) { + String newId = ctx.getRealIds().get(strDashboardId); + if (newId != null) { + DashboardId dashboardId = new DashboardId(UUID.fromString(newId)); + dashboardService.assignDashboardToEdge(ctx.getTenantId(), dashboardId, entity.getId()); + } else { + log.error("[{}] Edge: {} references non existing dashboard.", ctx.getTenantId(), entity.getName()); + throw new RuntimeException("Edge: " + entity.getName() + " references non existing dashboard."); + } + } + } + private void provisionAlarmRules(SolutionInstallContext ctx) { List cfs = loadListOfEntitiesIfFileExists(ctx.getTempDir(), "alarm_rules.json", new TypeReference<>() {}); cfs.addAll(loadListOfEntitiesFromDirectory(ctx.getTempDir(), "alarm_rules", CalculatedField.class)); @@ -933,30 +951,30 @@ public class DefaultSolutionService implements SolutionService { } private void provisionRelations(SolutionInstallContext ctx) { - for (var entry : ctx.getRelationDefinitions().entrySet()) { - EntityId entityId = entry.getKey(); - for (RelationDefinition relationDef : entry.getValue()) { - EntityId targetId = resolveRelatedEntityId(ctx, relationDef); - if (targetId == null) { - log.warn("[{}] Relation target not found: {} '{}'", ctx.getTenantId(), relationDef.getEntityType(), relationDef.getEntityName()); - continue; - } - EntityRelation relation = new EntityRelation(); - if (relationDef.getDirection() == EntitySearchDirection.FROM) { - relation.setFrom(entityId); - relation.setTo(targetId); + ctx.getRelationDefinitions().forEach((id, relations) -> { + for (RelationDefinition relationDef : relations) { + log.info("[{}] Saving relation: {}", id, relationDef); + EntityRelation entityRelation = new EntityRelation(); + EntityId otherId = resolveRelatedEntityId(relationDef, ctx); + if (EntitySearchDirection.FROM.equals(relationDef.getDirection())) { + entityRelation.setFrom(otherId); + entityRelation.setTo(id); } else { - relation.setFrom(targetId); - relation.setTo(entityId); + entityRelation.setFrom(id); + entityRelation.setTo(otherId); + } + entityRelation.setTypeGroup(RelationTypeGroup.COMMON); + entityRelation.setType(relationDef.getType()); + try { + relationService.save(ctx.getTenantId(), null, entityRelation, null); + } catch (Exception e) { + log.info("[{}] Failed to save relation: {}, cause: {}", id, relationDef, e.getMessage()); } - relation.setType(relationDef.getType()); - relation.setTypeGroup(RelationTypeGroup.COMMON); - relationService.saveRelation(ctx.getTenantId(), relation); } - } + }); } - private EntityId resolveRelatedEntityId(SolutionInstallContext ctx, RelationDefinition relationDef) { + private EntityId resolveRelatedEntityId(RelationDefinition relationDef, SolutionInstallContext ctx) { if (relationDef.getEntityType() == EntityType.TENANT) { return ctx.getTenantId(); } diff --git a/application/src/main/java/org/thingsboard/server/service/solutions/data/definition/EdgeDefinition.java b/application/src/main/java/org/thingsboard/server/service/solutions/data/definition/EdgeDefinition.java index 33034c93e9..5e8e7aa203 100644 --- a/application/src/main/java/org/thingsboard/server/service/solutions/data/definition/EdgeDefinition.java +++ b/application/src/main/java/org/thingsboard/server/service/solutions/data/definition/EdgeDefinition.java @@ -36,6 +36,7 @@ public class EdgeDefinition extends CustomerEntityDefinition { private List ruleChainIds = Collections.emptyList(); private List deviceIds = Collections.emptyList(); private List assetIds = Collections.emptyList(); + private List dashboardIds = Collections.emptyList(); @Override public EntityType getEntityType() { diff --git a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-update-dialog.component.scss b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-update-dialog.component.scss index a7ad4a2d3b..e7a4592437 100644 --- a/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-update-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-update-dialog.component.scss @@ -41,6 +41,7 @@ .tb-iot-hub-inline-spinner { display: inline-block; margin-right: 8px; + vertical-align: middle; } .tb-iot-hub-error-details {