Commit efd565d8b607ae384ef925a634d0002d4d79faec
1 parent
66af90bf
Added root rule chain for the edge. Part 2
Showing
31 changed files
with
542 additions
and
87 deletions
@@ -18,8 +18,13 @@ CREATE TABLE IF NOT EXISTS edge ( | @@ -18,8 +18,13 @@ CREATE TABLE IF NOT EXISTS edge ( | ||
18 | id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, | 18 | id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, |
19 | additional_info varchar, | 19 | additional_info varchar, |
20 | customer_id varchar(31), | 20 | customer_id varchar(31), |
21 | + root_rule_chain_id varchar(31), | ||
21 | configuration varchar(10000000), | 22 | configuration varchar(10000000), |
23 | + type varchar(255), | ||
22 | name varchar(255), | 24 | name varchar(255), |
25 | + label varchar(255), | ||
26 | + routing_key varchar(255), | ||
27 | + secret varchar(255), | ||
23 | search_text varchar(255), | 28 | search_text varchar(255), |
24 | tenant_id varchar(31) | 29 | tenant_id varchar(31) |
25 | ); | 30 | ); |
@@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
39 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | 39 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
40 | import org.thingsboard.server.common.data.relation.EntityRelation; | 40 | import org.thingsboard.server.common.data.relation.EntityRelation; |
41 | import org.thingsboard.server.common.data.rule.RuleChain; | 41 | import org.thingsboard.server.common.data.rule.RuleChain; |
42 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
42 | import org.thingsboard.server.common.data.rule.RuleNode; | 43 | import org.thingsboard.server.common.data.rule.RuleNode; |
43 | import org.thingsboard.server.common.msg.TbMsg; | 44 | import org.thingsboard.server.common.msg.TbMsg; |
44 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 45 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
@@ -97,17 +98,19 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -97,17 +98,19 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
97 | if (!started) { | 98 | if (!started) { |
98 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); | 99 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
99 | if (ruleChain != null) { | 100 | if (ruleChain != null) { |
100 | - ruleChainName = ruleChain.getName(); | ||
101 | - List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | ||
102 | - log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | ||
103 | - // Creating and starting the actors; | ||
104 | - for (RuleNode ruleNode : ruleNodeList) { | ||
105 | - log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | ||
106 | - ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | ||
107 | - nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | 101 | + if (ruleChain.getType().equals(RuleChainType.SYSTEM)) { |
102 | + ruleChainName = ruleChain.getName(); | ||
103 | + List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | ||
104 | + log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | ||
105 | + // Creating and starting the actors; | ||
106 | + for (RuleNode ruleNode : ruleNodeList) { | ||
107 | + log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | ||
108 | + ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | ||
109 | + nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | ||
110 | + } | ||
111 | + initRoutes(ruleChain, ruleNodeList); | ||
112 | + started = true; | ||
108 | } | 113 | } |
109 | - initRoutes(ruleChain, ruleNodeList); | ||
110 | - started = true; | ||
111 | } | 114 | } |
112 | } else { | 115 | } else { |
113 | onUpdate(context); | 116 | onUpdate(context); |
@@ -118,31 +121,35 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -118,31 +121,35 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
118 | public void onUpdate(ActorContext context) { | 121 | public void onUpdate(ActorContext context) { |
119 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); | 122 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
120 | if (ruleChain != null) { | 123 | if (ruleChain != null) { |
121 | - ruleChainName = ruleChain.getName(); | ||
122 | - List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | ||
123 | - log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | ||
124 | - for (RuleNode ruleNode : ruleNodeList) { | ||
125 | - RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); | ||
126 | - if (existing == null) { | ||
127 | - log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | ||
128 | - ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | ||
129 | - nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | ||
130 | - } else { | ||
131 | - log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | ||
132 | - existing.setSelf(ruleNode); | ||
133 | - existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); | 124 | + if (ruleChain.getType().equals(RuleChainType.SYSTEM)) { |
125 | + ruleChainName = ruleChain.getName(); | ||
126 | + List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | ||
127 | + log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | ||
128 | + for (RuleNode ruleNode : ruleNodeList) { | ||
129 | + RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); | ||
130 | + if (existing == null) { | ||
131 | + log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | ||
132 | + ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | ||
133 | + nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | ||
134 | + } else { | ||
135 | + log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | ||
136 | + existing.setSelf(ruleNode); | ||
137 | + existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); | ||
138 | + } | ||
134 | } | 139 | } |
135 | - } | ||
136 | 140 | ||
137 | - Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet()); | ||
138 | - List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList()); | ||
139 | - removedRules.forEach(ruleNodeId -> { | ||
140 | - log.trace("[{}][{}] Removing rule node [{}]", tenantId, entityId, ruleNodeId); | ||
141 | - RuleNodeCtx removed = nodeActors.remove(ruleNodeId); | ||
142 | - removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self); | ||
143 | - }); | 141 | + Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet()); |
142 | + List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList()); | ||
143 | + removedRules.forEach(ruleNodeId -> { | ||
144 | + log.trace("[{}][{}] Removing rule node [{}]", tenantId, entityId, ruleNodeId); | ||
145 | + RuleNodeCtx removed = nodeActors.remove(ruleNodeId); | ||
146 | + removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self); | ||
147 | + }); | ||
144 | 148 | ||
145 | - initRoutes(ruleChain, ruleNodeList); | 149 | + initRoutes(ruleChain, ruleNodeList); |
150 | + } else if (ruleChain.getType().equals(RuleChainType.EDGE)){ | ||
151 | + stop(context); | ||
152 | + } | ||
146 | } | 153 | } |
147 | } | 154 | } |
148 | 155 |
@@ -139,7 +139,7 @@ public class TenantActor extends RuleChainManagerActor { | @@ -139,7 +139,7 @@ public class TenantActor extends RuleChainManagerActor { | ||
139 | RuleChain ruleChain = null; | 139 | RuleChain ruleChain = null; |
140 | if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { | 140 | if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { |
141 | ruleChain = systemContext.getRuleChainService().findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); | 141 | ruleChain = systemContext.getRuleChainService().findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); |
142 | - if (RuleChainType.SYSTEM.equals(ruleChain.getType())) { | 142 | + if (ruleChain !=null && !RuleChainType.SYSTEM.equals(ruleChain.getType())) { |
143 | log.debug("[{}] Non SYSTEM rule chains are ignored and not started. Current rule chain type [{}]", tenantId, ruleChain.getType()); | 143 | log.debug("[{}] Non SYSTEM rule chains are ignored and not started. Current rule chain type [{}]", tenantId, ruleChain.getType()); |
144 | return; | 144 | return; |
145 | } | 145 | } |
@@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.Customer; | @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.Customer; | ||
30 | import org.thingsboard.server.common.data.Device; | 30 | import org.thingsboard.server.common.data.Device; |
31 | import org.thingsboard.server.common.data.EntitySubtype; | 31 | import org.thingsboard.server.common.data.EntitySubtype; |
32 | import org.thingsboard.server.common.data.EntityType; | 32 | import org.thingsboard.server.common.data.EntityType; |
33 | +import org.thingsboard.server.common.data.Tenant; | ||
33 | import org.thingsboard.server.common.data.audit.ActionType; | 34 | import org.thingsboard.server.common.data.audit.ActionType; |
34 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; | 35 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
35 | import org.thingsboard.server.common.data.edge.Edge; | 36 | import org.thingsboard.server.common.data.edge.Edge; |
@@ -37,9 +38,12 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | @@ -37,9 +38,12 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | ||
37 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 38 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
38 | import org.thingsboard.server.common.data.id.CustomerId; | 39 | import org.thingsboard.server.common.data.id.CustomerId; |
39 | import org.thingsboard.server.common.data.id.EdgeId; | 40 | import org.thingsboard.server.common.data.id.EdgeId; |
41 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
40 | import org.thingsboard.server.common.data.id.TenantId; | 42 | import org.thingsboard.server.common.data.id.TenantId; |
41 | import org.thingsboard.server.common.data.page.TextPageData; | 43 | import org.thingsboard.server.common.data.page.TextPageData; |
42 | import org.thingsboard.server.common.data.page.TextPageLink; | 44 | import org.thingsboard.server.common.data.page.TextPageLink; |
45 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
46 | +import org.thingsboard.server.common.data.rule.RuleChain; | ||
43 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 47 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
44 | import org.thingsboard.server.dao.model.ModelConstants; | 48 | import org.thingsboard.server.dao.model.ModelConstants; |
45 | import org.thingsboard.server.service.security.model.SecurityUser; | 49 | import org.thingsboard.server.service.security.model.SecurityUser; |
@@ -74,7 +78,8 @@ public class EdgeController extends BaseController { | @@ -74,7 +78,8 @@ public class EdgeController extends BaseController { | ||
74 | @ResponseBody | 78 | @ResponseBody |
75 | public Edge saveEdge(@RequestBody Edge edge) throws ThingsboardException { | 79 | public Edge saveEdge(@RequestBody Edge edge) throws ThingsboardException { |
76 | try { | 80 | try { |
77 | - edge.setTenantId(getCurrentUser().getTenantId()); | 81 | + TenantId tenantId = getCurrentUser().getTenantId(); |
82 | + edge.setTenantId(tenantId); | ||
78 | boolean created = edge.getId() == null; | 83 | boolean created = edge.getId() == null; |
79 | 84 | ||
80 | Operation operation = created ? Operation.CREATE : Operation.WRITE; | 85 | Operation operation = created ? Operation.CREATE : Operation.WRITE; |
@@ -84,6 +89,12 @@ public class EdgeController extends BaseController { | @@ -84,6 +89,12 @@ public class EdgeController extends BaseController { | ||
84 | 89 | ||
85 | Edge result = checkNotNull(edgeService.saveEdge(edge)); | 90 | Edge result = checkNotNull(edgeService.saveEdge(edge)); |
86 | 91 | ||
92 | + if (created) { | ||
93 | + RuleChain rootTenantRuleChain = ruleChainService.getRootTenantRuleChain(tenantId); | ||
94 | + ruleChainService.assignRuleChainToEdge(tenantId, rootTenantRuleChain.getId(), result.getId()); | ||
95 | + edgeService.setRootRuleChain(tenantId, result, rootTenantRuleChain.getId()); | ||
96 | + } | ||
97 | + | ||
87 | logEntityAction(result.getId(), result, null, created ? ActionType.ADDED : ActionType.UPDATED, null); | 98 | logEntityAction(result.getId(), result, null, created ? ActionType.ADDED : ActionType.UPDATED, null); |
88 | return result; | 99 | return result; |
89 | } catch (Exception e) { | 100 | } catch (Exception e) { |
@@ -250,6 +261,36 @@ public class EdgeController extends BaseController { | @@ -250,6 +261,36 @@ public class EdgeController extends BaseController { | ||
250 | } | 261 | } |
251 | } | 262 | } |
252 | 263 | ||
264 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
265 | + @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) | ||
266 | + @ResponseBody | ||
267 | + public Edge setRootRuleChain(@PathVariable(EDGE_ID) String strEdgeId, | ||
268 | + @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException { | ||
269 | + checkParameter(EDGE_ID, strEdgeId); | ||
270 | + checkParameter("ruleChainId", strRuleChainId); | ||
271 | + try { | ||
272 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
273 | + checkRuleChain(ruleChainId, Operation.WRITE); | ||
274 | + | ||
275 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
276 | + Edge edge = checkEdgeId(edgeId, Operation.WRITE); | ||
277 | + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.WRITE, | ||
278 | + edge.getId(), edge); | ||
279 | + | ||
280 | + Edge updatedEdge = edgeService.setRootRuleChain(getTenantId(), edge, ruleChainId); | ||
281 | + | ||
282 | + logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null); | ||
283 | + | ||
284 | + return updatedEdge; | ||
285 | + } catch (Exception e) { | ||
286 | + logEntityAction(emptyId(EntityType.EDGE), | ||
287 | + null, | ||
288 | + null, | ||
289 | + ActionType.UPDATED, e, strEdgeId); | ||
290 | + throw handleException(e); | ||
291 | + } | ||
292 | + } | ||
293 | + | ||
253 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | 294 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
254 | @RequestMapping(value = "/customer/{customerId}/edges", params = {"limit"}, method = RequestMethod.GET) | 295 | @RequestMapping(value = "/customer/{customerId}/edges", params = {"limit"}, method = RequestMethod.GET) |
255 | @ResponseBody | 296 | @ResponseBody |
@@ -59,6 +59,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; | @@ -59,6 +59,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; | ||
59 | import org.thingsboard.server.common.msg.TbMsg; | 59 | import org.thingsboard.server.common.msg.TbMsg; |
60 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 60 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
61 | import org.thingsboard.server.dao.event.EventService; | 61 | import org.thingsboard.server.dao.event.EventService; |
62 | +import org.thingsboard.server.dao.exception.DataValidationException; | ||
62 | import org.thingsboard.server.service.script.JsInvokeService; | 63 | import org.thingsboard.server.service.script.JsInvokeService; |
63 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; | 64 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
64 | import org.thingsboard.server.service.security.permission.Operation; | 65 | import org.thingsboard.server.service.security.permission.Operation; |
@@ -18,10 +18,12 @@ package org.thingsboard.server.dao.edge; | @@ -18,10 +18,12 @@ package org.thingsboard.server.dao.edge; | ||
18 | import com.google.common.util.concurrent.ListenableFuture; | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | import org.thingsboard.server.common.data.EntitySubtype; | 19 | import org.thingsboard.server.common.data.EntitySubtype; |
20 | import org.thingsboard.server.common.data.Event; | 20 | import org.thingsboard.server.common.data.Event; |
21 | +import org.thingsboard.server.common.data.Tenant; | ||
21 | import org.thingsboard.server.common.data.edge.Edge; | 22 | import org.thingsboard.server.common.data.edge.Edge; |
22 | import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | 23 | import org.thingsboard.server.common.data.edge.EdgeSearchQuery; |
23 | import org.thingsboard.server.common.data.id.CustomerId; | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
24 | import org.thingsboard.server.common.data.id.EdgeId; | 25 | import org.thingsboard.server.common.data.id.EdgeId; |
26 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
25 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
26 | import org.thingsboard.server.common.data.page.TextPageData; | 28 | import org.thingsboard.server.common.data.page.TextPageData; |
27 | import org.thingsboard.server.common.data.page.TextPageLink; | 29 | import org.thingsboard.server.common.data.page.TextPageLink; |
@@ -73,6 +75,8 @@ public interface EdgeService { | @@ -73,6 +75,8 @@ public interface EdgeService { | ||
73 | void pushEventToEdge(TenantId tenantId, TbMsg tbMsg); | 75 | void pushEventToEdge(TenantId tenantId, TbMsg tbMsg); |
74 | 76 | ||
75 | TimePageData<Event> findQueueEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); | 77 | TimePageData<Event> findQueueEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); |
78 | + | ||
79 | + Edge setRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId); | ||
76 | } | 80 | } |
77 | 81 | ||
78 | 82 |
@@ -124,7 +124,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | @@ -124,7 +124,7 @@ public class DashboardInfo extends SearchTextBased<DashboardId> implements HasNa | ||
124 | } | 124 | } |
125 | 125 | ||
126 | public boolean isAssignedToEdge(EdgeId edgeId) { | 126 | public boolean isAssignedToEdge(EdgeId edgeId) { |
127 | - return this.assignedEdges != null && this.assignedEdges.contains(new ShortEdgeInfo(edgeId, null)); | 127 | + return this.assignedEdges != null && this.assignedEdges.contains(new ShortEdgeInfo(edgeId, null, null)); |
128 | } | 128 | } |
129 | 129 | ||
130 | public ShortEdgeInfo getAssignedEdgeInfo(EdgeId edgeId) { | 130 | public ShortEdgeInfo getAssignedEdgeInfo(EdgeId edgeId) { |
@@ -19,6 +19,7 @@ import lombok.AllArgsConstructor; | @@ -19,6 +19,7 @@ import lombok.AllArgsConstructor; | ||
19 | import lombok.Getter; | 19 | import lombok.Getter; |
20 | import lombok.Setter; | 20 | import lombok.Setter; |
21 | import org.thingsboard.server.common.data.id.EdgeId; | 21 | import org.thingsboard.server.common.data.id.EdgeId; |
22 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
22 | 23 | ||
23 | @AllArgsConstructor | 24 | @AllArgsConstructor |
24 | public class ShortEdgeInfo { | 25 | public class ShortEdgeInfo { |
@@ -29,6 +30,9 @@ public class ShortEdgeInfo { | @@ -29,6 +30,9 @@ public class ShortEdgeInfo { | ||
29 | @Getter @Setter | 30 | @Getter @Setter |
30 | private String title; | 31 | private String title; |
31 | 32 | ||
33 | + @Getter @Setter | ||
34 | + private RuleChainId rootRuleChainId; | ||
35 | + | ||
32 | @Override | 36 | @Override |
33 | public boolean equals(Object o) { | 37 | public boolean equals(Object o) { |
34 | if (this == o) return true; | 38 | if (this == o) return true; |
@@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.ShortCustomerInfo; | @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.ShortCustomerInfo; | ||
29 | import org.thingsboard.server.common.data.ShortEdgeInfo; | 29 | import org.thingsboard.server.common.data.ShortEdgeInfo; |
30 | import org.thingsboard.server.common.data.id.CustomerId; | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
31 | import org.thingsboard.server.common.data.id.EdgeId; | 31 | import org.thingsboard.server.common.data.id.EdgeId; |
32 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
32 | import org.thingsboard.server.common.data.id.TenantId; | 33 | import org.thingsboard.server.common.data.id.TenantId; |
33 | 34 | ||
34 | @EqualsAndHashCode(callSuper = true) | 35 | @EqualsAndHashCode(callSuper = true) |
@@ -41,6 +42,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | @@ -41,6 +42,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | ||
41 | 42 | ||
42 | private TenantId tenantId; | 43 | private TenantId tenantId; |
43 | private CustomerId customerId; | 44 | private CustomerId customerId; |
45 | + private RuleChainId rootRuleChainId; | ||
44 | private String name; | 46 | private String name; |
45 | private String type; | 47 | private String type; |
46 | private String label; | 48 | private String label; |
@@ -60,6 +62,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | @@ -60,6 +62,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | ||
60 | super(edge); | 62 | super(edge); |
61 | this.tenantId = edge.getTenantId(); | 63 | this.tenantId = edge.getTenantId(); |
62 | this.customerId = edge.getCustomerId(); | 64 | this.customerId = edge.getCustomerId(); |
65 | + this.rootRuleChainId = edge.getRootRuleChainId(); | ||
63 | this.type = edge.getType(); | 66 | this.type = edge.getType(); |
64 | this.name = edge.getName(); | 67 | this.name = edge.getName(); |
65 | this.routingKey = edge.getRoutingKey(); | 68 | this.routingKey = edge.getRoutingKey(); |
@@ -69,7 +72,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | @@ -69,7 +72,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | ||
69 | 72 | ||
70 | @JsonIgnore | 73 | @JsonIgnore |
71 | public ShortEdgeInfo toShortEdgeInfo() { | 74 | public ShortEdgeInfo toShortEdgeInfo() { |
72 | - return new ShortEdgeInfo(id, name); | 75 | + return new ShortEdgeInfo(id, name, rootRuleChainId); |
73 | } | 76 | } |
74 | 77 | ||
75 | @Override | 78 | @Override |
@@ -94,7 +94,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im | @@ -94,7 +94,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im | ||
94 | } | 94 | } |
95 | 95 | ||
96 | public boolean isAssignedToEdge(EdgeId edgeId) { | 96 | public boolean isAssignedToEdge(EdgeId edgeId) { |
97 | - return this.assignedEdges != null && this.assignedEdges.contains(new ShortEdgeInfo(edgeId, null)); | 97 | + return this.assignedEdges != null && this.assignedEdges.contains(new ShortEdgeInfo(edgeId, null, null)); |
98 | } | 98 | } |
99 | 99 | ||
100 | public ShortEdgeInfo getAssignedEdgeInfo(EdgeId edgeId) { | 100 | public ShortEdgeInfo getAssignedEdgeInfo(EdgeId edgeId) { |
@@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | ||
44 | import org.thingsboard.server.common.data.id.CustomerId; | 44 | import org.thingsboard.server.common.data.id.CustomerId; |
45 | import org.thingsboard.server.common.data.id.EdgeId; | 45 | import org.thingsboard.server.common.data.id.EdgeId; |
46 | import org.thingsboard.server.common.data.id.EntityId; | 46 | import org.thingsboard.server.common.data.id.EntityId; |
47 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
47 | import org.thingsboard.server.common.data.id.TenantId; | 48 | import org.thingsboard.server.common.data.id.TenantId; |
48 | import org.thingsboard.server.common.data.page.TextPageData; | 49 | import org.thingsboard.server.common.data.page.TextPageData; |
49 | import org.thingsboard.server.common.data.page.TextPageLink; | 50 | import org.thingsboard.server.common.data.page.TextPageLink; |
@@ -472,6 +473,14 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic | @@ -472,6 +473,14 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic | ||
472 | return eventService.findEvents(tenantId, edgeId, DataConstants.EDGE_QUEUE_EVENT_TYPE, pageLink); | 473 | return eventService.findEvents(tenantId, edgeId, DataConstants.EDGE_QUEUE_EVENT_TYPE, pageLink); |
473 | } | 474 | } |
474 | 475 | ||
476 | + @Override | ||
477 | + public Edge setRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) { | ||
478 | + edge.setRootRuleChainId(ruleChainId); | ||
479 | + Edge saveEdge = saveEdge(edge); | ||
480 | + ruleChainService.updateEdgeRuleChains(tenantId, saveEdge.getId()); | ||
481 | + return saveEdge; | ||
482 | + } | ||
483 | + | ||
475 | private DataValidator<Edge> edgeValidator = | 484 | private DataValidator<Edge> edgeValidator = |
476 | new DataValidator<Edge>() { | 485 | new DataValidator<Edge>() { |
477 | 486 |
@@ -359,6 +359,7 @@ public class ModelConstants { | @@ -359,6 +359,7 @@ public class ModelConstants { | ||
359 | public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; | 359 | public static final String EDGE_COLUMN_FAMILY_NAME = "edge"; |
360 | public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; | 360 | public static final String EDGE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; |
361 | public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; | 361 | public static final String EDGE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; |
362 | + public static final String EDGE_ROOT_RULE_CHAIN_ID_PROPERTY = "root_rule_chain_id"; | ||
362 | public static final String EDGE_NAME_PROPERTY = "name"; | 363 | public static final String EDGE_NAME_PROPERTY = "name"; |
363 | public static final String EDGE_LABEL_PROPERTY = "label"; | 364 | public static final String EDGE_LABEL_PROPERTY = "label"; |
364 | public static final String EDGE_TYPE_PROPERTY = "type"; | 365 | public static final String EDGE_TYPE_PROPERTY = "type"; |
@@ -25,6 +25,7 @@ import lombok.Data; | @@ -25,6 +25,7 @@ import lombok.Data; | ||
25 | import org.thingsboard.server.common.data.edge.Edge; | 25 | import org.thingsboard.server.common.data.edge.Edge; |
26 | import org.thingsboard.server.common.data.id.CustomerId; | 26 | import org.thingsboard.server.common.data.id.CustomerId; |
27 | import org.thingsboard.server.common.data.id.EdgeId; | 27 | import org.thingsboard.server.common.data.id.EdgeId; |
28 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
28 | import org.thingsboard.server.common.data.id.TenantId; | 29 | import org.thingsboard.server.common.data.id.TenantId; |
29 | import org.thingsboard.server.dao.model.SearchTextEntity; | 30 | import org.thingsboard.server.dao.model.SearchTextEntity; |
30 | import org.thingsboard.server.dao.model.type.JsonCodec; | 31 | import org.thingsboard.server.dao.model.type.JsonCodec; |
@@ -37,6 +38,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION | @@ -37,6 +38,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION | ||
37 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; | 38 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; |
38 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; | 39 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; |
39 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; | 40 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; |
41 | +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROOT_RULE_CHAIN_ID_PROPERTY; | ||
40 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROUTING_KEY_PROPERTY; | 42 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROUTING_KEY_PROPERTY; |
41 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_SECRET_PROPERTY; | 43 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_SECRET_PROPERTY; |
42 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; | 44 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
@@ -60,6 +62,9 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | @@ -60,6 +62,9 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | ||
60 | @Column(name = EDGE_CUSTOMER_ID_PROPERTY) | 62 | @Column(name = EDGE_CUSTOMER_ID_PROPERTY) |
61 | private UUID customerId; | 63 | private UUID customerId; |
62 | 64 | ||
65 | + @Column(name = EDGE_ROOT_RULE_CHAIN_ID_PROPERTY) | ||
66 | + private UUID rootRuleChainId; | ||
67 | + | ||
63 | @Column(name = EDGE_TYPE_PROPERTY) | 68 | @Column(name = EDGE_TYPE_PROPERTY) |
64 | private String type; | 69 | private String type; |
65 | 70 | ||
@@ -95,6 +100,12 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | @@ -95,6 +100,12 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | ||
95 | if (edge.getTenantId() != null) { | 100 | if (edge.getTenantId() != null) { |
96 | this.tenantId = edge.getTenantId().getId(); | 101 | this.tenantId = edge.getTenantId().getId(); |
97 | } | 102 | } |
103 | + if (edge.getCustomerId() != null) { | ||
104 | + this.customerId = edge.getCustomerId().getId(); | ||
105 | + } | ||
106 | + if (edge.getRootRuleChainId() != null) { | ||
107 | + this.rootRuleChainId = edge.getRootRuleChainId().getId(); | ||
108 | + } | ||
98 | this.type = edge.getType(); | 109 | this.type = edge.getType(); |
99 | this.name = edge.getName(); | 110 | this.name = edge.getName(); |
100 | this.label = edge.getLabel(); | 111 | this.label = edge.getLabel(); |
@@ -119,6 +130,9 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | @@ -119,6 +130,9 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | ||
119 | if (customerId != null) { | 130 | if (customerId != null) { |
120 | edge.setCustomerId(new CustomerId(customerId)); | 131 | edge.setCustomerId(new CustomerId(customerId)); |
121 | } | 132 | } |
133 | + if (rootRuleChainId != null) { | ||
134 | + edge.setRootRuleChainId(new RuleChainId(rootRuleChainId)); | ||
135 | + } | ||
122 | edge.setType(type); | 136 | edge.setType(type); |
123 | edge.setName(name); | 137 | edge.setName(name); |
124 | edge.setLabel(label); | 138 | edge.setLabel(label); |
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at | 6 | * You may obtain a copy of the License at |
7 | * | 7 | * |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * | 9 | * |
10 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.UUIDConverter; | @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.UUIDConverter; | ||
25 | import org.thingsboard.server.common.data.edge.Edge; | 25 | import org.thingsboard.server.common.data.edge.Edge; |
26 | import org.thingsboard.server.common.data.id.CustomerId; | 26 | import org.thingsboard.server.common.data.id.CustomerId; |
27 | import org.thingsboard.server.common.data.id.EdgeId; | 27 | import org.thingsboard.server.common.data.id.EdgeId; |
28 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
28 | import org.thingsboard.server.common.data.id.TenantId; | 29 | import org.thingsboard.server.common.data.id.TenantId; |
29 | import org.thingsboard.server.dao.model.BaseSqlEntity; | 30 | import org.thingsboard.server.dao.model.BaseSqlEntity; |
30 | import org.thingsboard.server.dao.model.ModelConstants; | 31 | import org.thingsboard.server.dao.model.ModelConstants; |
@@ -39,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY | @@ -39,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY | ||
39 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; | 40 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; |
40 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; | 41 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; |
41 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; | 42 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; |
43 | +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROOT_RULE_CHAIN_ID_PROPERTY; | ||
42 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROUTING_KEY_PROPERTY; | 44 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROUTING_KEY_PROPERTY; |
43 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_SECRET_PROPERTY; | 45 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_SECRET_PROPERTY; |
44 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; | 46 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
@@ -58,6 +60,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | @@ -58,6 +60,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | ||
58 | @Column(name = EDGE_CUSTOMER_ID_PROPERTY) | 60 | @Column(name = EDGE_CUSTOMER_ID_PROPERTY) |
59 | private String customerId; | 61 | private String customerId; |
60 | 62 | ||
63 | + @Column(name = EDGE_ROOT_RULE_CHAIN_ID_PROPERTY) | ||
64 | + private String rootRuleChainId; | ||
65 | + | ||
61 | @Column(name = EDGE_TYPE_PROPERTY) | 66 | @Column(name = EDGE_TYPE_PROPERTY) |
62 | private String type; | 67 | private String type; |
63 | 68 | ||
@@ -98,6 +103,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | @@ -98,6 +103,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | ||
98 | if (edge.getCustomerId() != null) { | 103 | if (edge.getCustomerId() != null) { |
99 | this.customerId = UUIDConverter.fromTimeUUID(edge.getCustomerId().getId()); | 104 | this.customerId = UUIDConverter.fromTimeUUID(edge.getCustomerId().getId()); |
100 | } | 105 | } |
106 | + if (edge.getRootRuleChainId() != null) { | ||
107 | + this.rootRuleChainId = UUIDConverter.fromTimeUUID(edge.getRootRuleChainId().getId()); | ||
108 | + } | ||
101 | this.type = edge.getType(); | 109 | this.type = edge.getType(); |
102 | this.name = edge.getName(); | 110 | this.name = edge.getName(); |
103 | this.label = edge.getLabel(); | 111 | this.label = edge.getLabel(); |
@@ -131,6 +139,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | @@ -131,6 +139,9 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | ||
131 | if (customerId != null) { | 139 | if (customerId != null) { |
132 | edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); | 140 | edge.setCustomerId(new CustomerId(UUIDConverter.fromString(customerId))); |
133 | } | 141 | } |
142 | + if (rootRuleChainId != null) { | ||
143 | + edge.setRootRuleChainId(new RuleChainId(UUIDConverter.fromString(rootRuleChainId))); | ||
144 | + } | ||
134 | edge.setType(type); | 145 | edge.setType(type); |
135 | edge.setName(name); | 146 | edge.setName(name); |
136 | edge.setLabel(label); | 147 | edge.setLabel(label); |
@@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; | @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired; | ||
25 | import org.springframework.stereotype.Service; | 25 | import org.springframework.stereotype.Service; |
26 | import org.thingsboard.server.common.data.BaseData; | 26 | import org.thingsboard.server.common.data.BaseData; |
27 | import org.thingsboard.server.common.data.EntityType; | 27 | import org.thingsboard.server.common.data.EntityType; |
28 | +import org.thingsboard.server.common.data.ShortEdgeInfo; | ||
28 | import org.thingsboard.server.common.data.Tenant; | 29 | import org.thingsboard.server.common.data.Tenant; |
29 | import org.thingsboard.server.common.data.edge.Edge; | 30 | import org.thingsboard.server.common.data.edge.Edge; |
30 | import org.thingsboard.server.common.data.id.EdgeId; | 31 | import org.thingsboard.server.common.data.id.EdgeId; |
@@ -42,6 +43,7 @@ import org.thingsboard.server.common.data.rule.NodeConnectionInfo; | @@ -42,6 +43,7 @@ import org.thingsboard.server.common.data.rule.NodeConnectionInfo; | ||
42 | import org.thingsboard.server.common.data.rule.RuleChain; | 43 | import org.thingsboard.server.common.data.rule.RuleChain; |
43 | import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; | 44 | import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; |
44 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; | 45 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
46 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
45 | import org.thingsboard.server.common.data.rule.RuleNode; | 47 | import org.thingsboard.server.common.data.rule.RuleNode; |
46 | import org.thingsboard.server.dao.edge.EdgeDao; | 48 | import org.thingsboard.server.dao.edge.EdgeDao; |
47 | import org.thingsboard.server.dao.edge.EdgeService; | 49 | import org.thingsboard.server.dao.edge.EdgeService; |
@@ -116,6 +118,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | @@ -116,6 +118,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | ||
116 | createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), | 118 | createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), |
117 | EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); | 119 | EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); |
118 | ruleChain.setRoot(true); | 120 | ruleChain.setRoot(true); |
121 | + ruleChain.setType(RuleChainType.SYSTEM); | ||
119 | ruleChainDao.save(tenantId, ruleChain); | 122 | ruleChainDao.save(tenantId, ruleChain); |
120 | return true; | 123 | return true; |
121 | } catch (ExecutionException | InterruptedException e) { | 124 | } catch (ExecutionException | InterruptedException e) { |
@@ -359,8 +362,17 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | @@ -359,8 +362,17 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | ||
359 | public void deleteRuleChainById(TenantId tenantId, RuleChainId ruleChainId) { | 362 | public void deleteRuleChainById(TenantId tenantId, RuleChainId ruleChainId) { |
360 | Validator.validateId(ruleChainId, "Incorrect rule chain id for delete request."); | 363 | Validator.validateId(ruleChainId, "Incorrect rule chain id for delete request."); |
361 | RuleChain ruleChain = ruleChainDao.findById(tenantId, ruleChainId.getId()); | 364 | RuleChain ruleChain = ruleChainDao.findById(tenantId, ruleChainId.getId()); |
362 | - if (ruleChain != null && ruleChain.isRoot()) { | ||
363 | - throw new DataValidationException("Deletion of Root Tenant Rule Chain is prohibited!"); | 365 | + if (ruleChain != null) { |
366 | + if (ruleChain.isRoot()) { | ||
367 | + throw new DataValidationException("Deletion of Root Tenant Rule Chain is prohibited!"); | ||
368 | + } | ||
369 | + if (ruleChain.getAssignedEdges() != null && !ruleChain.getAssignedEdges().isEmpty()) { | ||
370 | + for (ShortEdgeInfo assignedEdge : ruleChain.getAssignedEdges()) { | ||
371 | + if (assignedEdge.getRootRuleChainId() != null && assignedEdge.getRootRuleChainId().equals(ruleChainId)) { | ||
372 | + throw new DataValidationException("Can't delete rule chain that is root for edge [" + assignedEdge.getTitle() + "]. Please assign another root rule chain first to the edge!"); | ||
373 | + } | ||
374 | + } | ||
375 | + } | ||
364 | } | 376 | } |
365 | checkRuleNodesAndDelete(tenantId, ruleChainId); | 377 | checkRuleNodesAndDelete(tenantId, ruleChainId); |
366 | } | 378 | } |
@@ -398,13 +410,16 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | @@ -398,13 +410,16 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | ||
398 | RuleChain ruleChain = findRuleChainById(tenantId, ruleChainId); | 410 | RuleChain ruleChain = findRuleChainById(tenantId, ruleChainId); |
399 | Edge edge = edgeDao.findById(tenantId, edgeId.getId()); | 411 | Edge edge = edgeDao.findById(tenantId, edgeId.getId()); |
400 | if (edge == null) { | 412 | if (edge == null) { |
401 | - throw new DataValidationException("Can't unassign ruleChain from non-existent edge!"); | 413 | + throw new DataValidationException("Can't unassign rule chain from non-existent edge!"); |
414 | + } | ||
415 | + if (edge.getRootRuleChainId() != null && edge.getRootRuleChainId().equals(ruleChainId)) { | ||
416 | + throw new DataValidationException("Can't unassign root rule chain from edge [" + edge.getName() + "]. Please assign another root rule chain first!"); | ||
402 | } | 417 | } |
403 | if (ruleChain.removeAssignedEdge(edge)) { | 418 | if (ruleChain.removeAssignedEdge(edge)) { |
404 | try { | 419 | try { |
405 | deleteRelation(tenantId, new EntityRelation(edgeId, ruleChainId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); | 420 | deleteRelation(tenantId, new EntityRelation(edgeId, ruleChainId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE)); |
406 | } catch (ExecutionException | InterruptedException e) { | 421 | } catch (ExecutionException | InterruptedException e) { |
407 | - log.warn("[{}] Failed to delete ruleChain relation. Edge Id: [{}]", ruleChainId, edgeId); | 422 | + log.warn("[{}] Failed to delete rule chain relation. Edge Id: [{}]", ruleChainId, edgeId); |
408 | throw new RuntimeException(e); | 423 | throw new RuntimeException(e); |
409 | } | 424 | } |
410 | return saveRuleChain(ruleChain); | 425 | return saveRuleChain(ruleChain); |
@@ -442,13 +457,13 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | @@ -442,13 +457,13 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC | ||
442 | Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); | 457 | Validator.validateId(tenantId, "Incorrect tenantId " + tenantId); |
443 | Validator.validateId(edgeId, "Incorrect customerId " + edgeId); | 458 | Validator.validateId(edgeId, "Incorrect customerId " + edgeId); |
444 | Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); | 459 | Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink); |
445 | - ListenableFuture<List<RuleChain>> dashboards = ruleChainDao.findRuleChainsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); | 460 | + ListenableFuture<List<RuleChain>> ruleChains = ruleChainDao.findRuleChainsByTenantIdAndEdgeId(tenantId.getId(), edgeId.getId(), pageLink); |
446 | 461 | ||
447 | - return Futures.transform(dashboards, new Function<List<RuleChain>, TimePageData<RuleChain>>() { | 462 | + return Futures.transform(ruleChains, new Function<List<RuleChain>, TimePageData<RuleChain>>() { |
448 | @Nullable | 463 | @Nullable |
449 | @Override | 464 | @Override |
450 | - public TimePageData<RuleChain> apply(@Nullable List<RuleChain> RuleChain) { | ||
451 | - return new TimePageData<>(RuleChain, pageLink); | 465 | + public TimePageData<RuleChain> apply(@Nullable List<RuleChain> ruleChain) { |
466 | + return new TimePageData<>(ruleChain, pageLink); | ||
452 | } | 467 | } |
453 | }); | 468 | }); |
454 | } | 469 | } |
@@ -47,5 +47,4 @@ public interface RuleChainDao extends Dao<RuleChain> { | @@ -47,5 +47,4 @@ public interface RuleChainDao extends Dao<RuleChain> { | ||
47 | * @return the list of rule chain objects | 47 | * @return the list of rule chain objects |
48 | */ | 48 | */ |
49 | ListenableFuture<List<RuleChain>> findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink); | 49 | ListenableFuture<List<RuleChain>> findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink); |
50 | - | ||
51 | } | 50 | } |
@@ -88,5 +88,4 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R | @@ -88,5 +88,4 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R | ||
88 | return Futures.successfulAsList(ruleChainFutures); | 88 | return Futures.successfulAsList(ruleChainFutures); |
89 | }); | 89 | }); |
90 | } | 90 | } |
91 | - | ||
92 | } | 91 | } |
@@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS edge ( | @@ -254,6 +254,7 @@ CREATE TABLE IF NOT EXISTS edge ( | ||
254 | id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, | 254 | id varchar(31) NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, |
255 | additional_info varchar, | 255 | additional_info varchar, |
256 | customer_id varchar(31), | 256 | customer_id varchar(31), |
257 | + root_rule_chain_id varchar(31), | ||
257 | configuration varchar(10000000), | 258 | configuration varchar(10000000), |
258 | type varchar(255), | 259 | type varchar(255), |
259 | name varchar(255), | 260 | name varchar(255), |
@@ -31,7 +31,8 @@ function EdgeService($http, $q, customerService) { | @@ -31,7 +31,8 @@ function EdgeService($http, $q, customerService) { | ||
31 | getCustomerEdges: getCustomerEdges, | 31 | getCustomerEdges: getCustomerEdges, |
32 | assignEdgeToCustomer: assignEdgeToCustomer, | 32 | assignEdgeToCustomer: assignEdgeToCustomer, |
33 | unassignEdgeFromCustomer: unassignEdgeFromCustomer, | 33 | unassignEdgeFromCustomer: unassignEdgeFromCustomer, |
34 | - makeEdgePublic: makeEdgePublic | 34 | + makeEdgePublic: makeEdgePublic, |
35 | + setRootRuleChain: setRootRuleChain | ||
35 | }; | 36 | }; |
36 | 37 | ||
37 | return service; | 38 | return service; |
@@ -229,4 +230,15 @@ function EdgeService($http, $q, customerService) { | @@ -229,4 +230,15 @@ function EdgeService($http, $q, customerService) { | ||
229 | }); | 230 | }); |
230 | return deferred.promise; | 231 | return deferred.promise; |
231 | } | 232 | } |
233 | + | ||
234 | + function setRootRuleChain(edgeId, ruleChainId) { | ||
235 | + var deferred = $q.defer(); | ||
236 | + var url = '/api/edge/' + edgeId + '/' + ruleChainId + '/root'; | ||
237 | + $http.post(url).then(function success(response) { | ||
238 | + deferred.resolve(response.data); | ||
239 | + }, function fail() { | ||
240 | + deferred.reject(); | ||
241 | + }); | ||
242 | + return deferred.promise; | ||
243 | + } | ||
232 | } | 244 | } |
@@ -19,6 +19,7 @@ import addEdgeTemplate from './add-edge.tpl.html'; | @@ -19,6 +19,7 @@ import addEdgeTemplate from './add-edge.tpl.html'; | ||
19 | import edgeCard from './edge-card.tpl.html'; | 19 | import edgeCard from './edge-card.tpl.html'; |
20 | import assignToCustomerTemplate from './assign-to-customer.tpl.html'; | 20 | import assignToCustomerTemplate from './assign-to-customer.tpl.html'; |
21 | import addEdgesToCustomerTemplate from './add-edges-to-customer.tpl.html'; | 21 | import addEdgesToCustomerTemplate from './add-edges-to-customer.tpl.html'; |
22 | +import setRootRuleChainToEdgesTemplate from './set-root-rule-chain-to-edges.tpl.html'; | ||
22 | 23 | ||
23 | /* eslint-enable import/no-unresolved, import/default */ | 24 | /* eslint-enable import/no-unresolved, import/default */ |
24 | 25 | ||
@@ -47,8 +48,8 @@ export function EdgeCardController(types) { | @@ -47,8 +48,8 @@ export function EdgeCardController(types) { | ||
47 | 48 | ||
48 | 49 | ||
49 | /*@ngInject*/ | 50 | /*@ngInject*/ |
50 | -export function EdgeController($rootScope, userService, edgeService, customerService, $state, $stateParams, | ||
51 | - $document, $mdDialog, $q, $translate, types, importExport) { | 51 | +export function EdgeController($rootScope, userService, edgeService, customerService, ruleChainService, |
52 | + $state, $stateParams, $document, $mdDialog, $q, $translate, types, importExport) { | ||
52 | 53 | ||
53 | var customerId = $stateParams.customerId; | 54 | var customerId = $stateParams.customerId; |
54 | 55 | ||
@@ -295,6 +296,19 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | @@ -295,6 +296,19 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | ||
295 | edgeGroupActionsList.push( | 296 | edgeGroupActionsList.push( |
296 | { | 297 | { |
297 | onAction: function ($event, items) { | 298 | onAction: function ($event, items) { |
299 | + setRootRuleChainToEdges($event, items); | ||
300 | + }, | ||
301 | + name: function() { return $translate.instant('edge.set-root-rule-chain-to-edges') }, | ||
302 | + details: function(selectedCount) { | ||
303 | + return $translate.instant('edge.set-root-rule-chain-to-edges-text', {count: selectedCount}, "messageformat"); | ||
304 | + }, | ||
305 | + icon: "flag" | ||
306 | + } | ||
307 | + ); | ||
308 | + | ||
309 | + edgeGroupActionsList.push( | ||
310 | + { | ||
311 | + onAction: function ($event, items) { | ||
298 | assignEdgesToCustomer($event, items); | 312 | assignEdgesToCustomer($event, items); |
299 | }, | 313 | }, |
300 | name: function() { return $translate.instant('edge.assign-edges') }, | 314 | name: function() { return $translate.instant('edge.assign-edges') }, |
@@ -305,8 +319,6 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | @@ -305,8 +319,6 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | ||
305 | } | 319 | } |
306 | ); | 320 | ); |
307 | 321 | ||
308 | - | ||
309 | - | ||
310 | edgeGroupActionsList.push( | 322 | edgeGroupActionsList.push( |
311 | { | 323 | { |
312 | onAction: function ($event) { | 324 | onAction: function ($event) { |
@@ -318,9 +330,7 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | @@ -318,9 +330,7 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | ||
318 | } | 330 | } |
319 | ); | 331 | ); |
320 | 332 | ||
321 | - | ||
322 | - | ||
323 | - } else if (vm.edgesScope === 'customer' || vm.edgesScope === 'customer_user') { | 333 | + } else if (vm.edgesScope === 'customer' || vm.edgesScope === 'customer_user') { |
324 | fetchEdgesFunction = function (pageLink, edgeType) { | 334 | fetchEdgesFunction = function (pageLink, edgeType) { |
325 | return edgeService.getCustomerEdges(customerId, pageLink, true, null, edgeType); | 335 | return edgeService.getCustomerEdges(customerId, pageLink, true, null, edgeType); |
326 | }; | 336 | }; |
@@ -524,6 +534,50 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | @@ -524,6 +534,50 @@ export function EdgeController($rootScope, userService, edgeService, customerSer | ||
524 | }); | 534 | }); |
525 | } | 535 | } |
526 | 536 | ||
537 | + function setRootRuleChainToEdges($event, items) { | ||
538 | + var edgeIds = []; | ||
539 | + for (var id in items.selections) { | ||
540 | + edgeIds.push(id); | ||
541 | + } | ||
542 | + setRootRuleChain($event, edgeIds); | ||
543 | + } | ||
544 | + | ||
545 | + function setRootRuleChain($event, edgeIds) { | ||
546 | + if ($event) { | ||
547 | + $event.stopPropagation(); | ||
548 | + } | ||
549 | + var pageSize = 10; | ||
550 | + ruleChainService.getRuleChains({limit: pageSize, textSearch: ''}).then( | ||
551 | + function success(_ruleChains) { | ||
552 | + var ruleChains = { | ||
553 | + pageSize: pageSize, | ||
554 | + data: _ruleChains.data, | ||
555 | + nextPageLink: _ruleChains.nextPageLink, | ||
556 | + selection: null, | ||
557 | + hasNext: _ruleChains.hasNext, | ||
558 | + pending: false | ||
559 | + }; | ||
560 | + if (ruleChains.hasNext) { | ||
561 | + ruleChains.nextPageLink.limit = pageSize; | ||
562 | + } | ||
563 | + $mdDialog.show({ | ||
564 | + controller: 'SetRootRuleChainToEdgesController', | ||
565 | + controllerAs: 'vm', | ||
566 | + templateUrl: setRootRuleChainToEdgesTemplate, | ||
567 | + locals: {edgeIds: edgeIds, ruleChains: ruleChains}, | ||
568 | + parent: angular.element($document[0].body), | ||
569 | + fullscreen: true, | ||
570 | + targetEvent: $event | ||
571 | + }).then(function () { | ||
572 | + vm.grid.refreshList(); | ||
573 | + }, function () { | ||
574 | + }); | ||
575 | + }, | ||
576 | + function fail() { | ||
577 | + }); | ||
578 | + } | ||
579 | + | ||
580 | + | ||
527 | function assignEdgesToCustomer($event, items) { | 581 | function assignEdgesToCustomer($event, items) { |
528 | var edgeIds = []; | 582 | var edgeIds = []; |
529 | for (var id in items.selections) { | 583 | for (var id in items.selections) { |
@@ -23,6 +23,7 @@ import EdgeRoutes from './edge.routes'; | @@ -23,6 +23,7 @@ import EdgeRoutes from './edge.routes'; | ||
23 | import {EdgeController, EdgeCardController} from './edge.controller'; | 23 | import {EdgeController, EdgeCardController} from './edge.controller'; |
24 | import AssignEdgeToCustomerController from './assign-to-customer.controller'; | 24 | import AssignEdgeToCustomerController from './assign-to-customer.controller'; |
25 | import AddEdgesToCustomerController from './add-edges-to-customer.controller'; | 25 | import AddEdgesToCustomerController from './add-edges-to-customer.controller'; |
26 | +import SetRootRuleChainToEdgesController from './set-root-rule-chain-to-edges.controller'; | ||
26 | import EdgeDirective from './edge.directive'; | 27 | import EdgeDirective from './edge.directive'; |
27 | 28 | ||
28 | export default angular.module('thingsboard.edge', [ | 29 | export default angular.module('thingsboard.edge', [ |
@@ -37,5 +38,6 @@ export default angular.module('thingsboard.edge', [ | @@ -37,5 +38,6 @@ export default angular.module('thingsboard.edge', [ | ||
37 | .controller('EdgeCardController', EdgeCardController) | 38 | .controller('EdgeCardController', EdgeCardController) |
38 | .controller('AssignEdgeToCustomerController', AssignEdgeToCustomerController) | 39 | .controller('AssignEdgeToCustomerController', AssignEdgeToCustomerController) |
39 | .controller('AddEdgesToCustomerController', AddEdgesToCustomerController) | 40 | .controller('AddEdgesToCustomerController', AddEdgesToCustomerController) |
41 | + .controller('SetRootRuleChainToEdgesController', SetRootRuleChainToEdgesController) | ||
40 | .directive('tbEdge', EdgeDirective) | 42 | .directive('tbEdge', EdgeDirective) |
41 | .name; | 43 | .name; |
1 | +/* | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +/*@ngInject*/ | ||
17 | +export default function SetRootRuleChainToEdgesController(ruleChainService, edgeService, $mdDialog, $q, edgeIds, ruleChains) { | ||
18 | + | ||
19 | + var vm = this; | ||
20 | + | ||
21 | + vm.ruleChains = ruleChains; | ||
22 | + vm.searchText = ''; | ||
23 | + | ||
24 | + vm.assign = assign; | ||
25 | + vm.cancel = cancel; | ||
26 | + vm.isRuleChainSelected = isRuleChainSelected; | ||
27 | + vm.hasData = hasData; | ||
28 | + vm.noData = noData; | ||
29 | + vm.searchRuleChainTextUpdated = searchRuleChainTextUpdated; | ||
30 | + vm.toggleRuleChainSelection = toggleRuleChainSelection; | ||
31 | + | ||
32 | + vm.theRuleChains = { | ||
33 | + getItemAtIndex: function (index) { | ||
34 | + if (index > vm.ruleChains.data.length) { | ||
35 | + vm.theRuleChains.fetchMoreItems_(index); | ||
36 | + return null; | ||
37 | + } | ||
38 | + var item = vm.ruleChains.data[index]; | ||
39 | + if (item) { | ||
40 | + item.indexNumber = index + 1; | ||
41 | + } | ||
42 | + return item; | ||
43 | + }, | ||
44 | + | ||
45 | + getLength: function () { | ||
46 | + if (vm.ruleChains.hasNext) { | ||
47 | + return vm.ruleChains.data.length + vm.ruleChains.nextPageLink.limit; | ||
48 | + } else { | ||
49 | + return vm.ruleChains.data.length; | ||
50 | + } | ||
51 | + }, | ||
52 | + | ||
53 | + fetchMoreItems_: function () { | ||
54 | + if (vm.ruleChains.hasNext && !vm.ruleChains.pending) { | ||
55 | + vm.ruleChains.pending = true; | ||
56 | + ruleChainService.getRuleChains(vm.ruleChains.nextPageLink).then( | ||
57 | + function success(ruleChains) { | ||
58 | + vm.ruleChains.data = vm.ruleChains.data.concat(ruleChains.data); | ||
59 | + vm.ruleChains.nextPageLink = ruleChains.nextPageLink; | ||
60 | + vm.ruleChains.hasNext = ruleChains.hasNext; | ||
61 | + if (vm.ruleChains.hasNext) { | ||
62 | + vm.ruleChains.nextPageLink.limit = vm.ruleChains.pageSize; | ||
63 | + } | ||
64 | + vm.ruleChains.pending = false; | ||
65 | + }, | ||
66 | + function fail() { | ||
67 | + vm.ruleChains.hasNext = false; | ||
68 | + vm.ruleChains.pending = false; | ||
69 | + }); | ||
70 | + } | ||
71 | + } | ||
72 | + }; | ||
73 | + | ||
74 | + function cancel() { | ||
75 | + $mdDialog.cancel(); | ||
76 | + } | ||
77 | + | ||
78 | + function assign() { | ||
79 | + var assignTasks = []; | ||
80 | + for (var i=0;i<edgeIds.length;i++) { | ||
81 | + assignTasks.push(ruleChainService.assignRuleChainToEdge(edgeIds[i], vm.ruleChains.selection.id.id)); | ||
82 | + } | ||
83 | + $q.all(assignTasks).then(function () { | ||
84 | + var setRootTasks = []; | ||
85 | + for (var j=0;j<edgeIds.length;j++) { | ||
86 | + setRootTasks.push(edgeService.setRootRuleChain(edgeIds[j], vm.ruleChains.selection.id.id)); | ||
87 | + } | ||
88 | + $q.all(setRootTasks).then(function () { | ||
89 | + $mdDialog.hide(); | ||
90 | + }); | ||
91 | + }); | ||
92 | + } | ||
93 | + | ||
94 | + function noData() { | ||
95 | + return vm.ruleChains.data.length == 0 && !vm.ruleChains.hasNext; | ||
96 | + } | ||
97 | + | ||
98 | + function hasData() { | ||
99 | + return vm.ruleChains.data.length > 0; | ||
100 | + } | ||
101 | + | ||
102 | + function toggleRuleChainSelection($event, ruleChain) { | ||
103 | + $event.stopPropagation(); | ||
104 | + if (vm.isRuleChainSelected(ruleChain)) { | ||
105 | + vm.ruleChains.selection = null; | ||
106 | + } else { | ||
107 | + vm.ruleChains.selection = ruleChain; | ||
108 | + } | ||
109 | + } | ||
110 | + | ||
111 | + function isRuleChainSelected(ruleChain) { | ||
112 | + return vm.ruleChains.selection != null && ruleChain && | ||
113 | + ruleChain.id.id === vm.ruleChains.selection.id.id; | ||
114 | + } | ||
115 | + | ||
116 | + function searchRuleChainTextUpdated() { | ||
117 | + vm.ruleChains = { | ||
118 | + pageSize: vm.ruleChains.pageSize, | ||
119 | + data: [], | ||
120 | + nextPageLink: { | ||
121 | + limit: vm.ruleChains.pageSize, | ||
122 | + textSearch: vm.searchText | ||
123 | + }, | ||
124 | + selection: null, | ||
125 | + hasNext: true, | ||
126 | + pending: false | ||
127 | + }; | ||
128 | + } | ||
129 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<md-dialog aria-label="{{ 'edge.set-root-rule-chain-to-edges' | translate }}"> | ||
19 | + <form name="theForm" ng-submit="vm.assign()"> | ||
20 | + <md-toolbar> | ||
21 | + <div class="md-toolbar-tools"> | ||
22 | + <h2 translate>edge.set-root-rule-chain-to-edges</h2> | ||
23 | + <span flex></span> | ||
24 | + <md-button class="md-icon-button" ng-click="vm.cancel()"> | ||
25 | + <ng-md-icon icon="close" aria-label="{{ 'dialog.close' | translate }}"></ng-md-icon> | ||
26 | + </md-button> | ||
27 | + </div> | ||
28 | + </md-toolbar> | ||
29 | + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> | ||
30 | + <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> | ||
31 | + <md-dialog-content> | ||
32 | + <div class="md-dialog-content"> | ||
33 | + <fieldset> | ||
34 | + <span translate>edge.set-root-rule-chain-text</span> | ||
35 | + <md-input-container class="md-block" style='margin-bottom: 0px;'> | ||
36 | + <label> </label> | ||
37 | + <md-icon aria-label="{{ 'action.search' | translate }}" class="material-icons"> | ||
38 | + search | ||
39 | + </md-icon> | ||
40 | + <input id="rule-chain-search" autofocus ng-model="vm.searchText" | ||
41 | + ng-change="vm.searchRuleChainTextUpdated()" | ||
42 | + placeholder="{{ 'common.enter-search' | translate }}"/> | ||
43 | + </md-input-container> | ||
44 | + <div style='min-height: 150px;'> | ||
45 | + <span translate layout-align="center center" | ||
46 | + style="text-transform: uppercase; display: flex; height: 150px;" | ||
47 | + class="md-subhead" | ||
48 | + ng-show="vm.noData()">rulechain.no-rulechains-text</span> | ||
49 | + <md-virtual-repeat-container ng-show="vm.hasData()" | ||
50 | + tb-scope-element="repeatContainer" md-top-index="vm.topIndex" flex | ||
51 | + style='min-height: 150px; width: 100%;'> | ||
52 | + <md-list> | ||
53 | + <md-list-item md-virtual-repeat="ruleChain in vm.theRuleChains" md-on-demand | ||
54 | + class="repeated-item" flex> | ||
55 | + <md-checkbox ng-click="vm.toggleRuleChainSelection($event, ruleChain)" | ||
56 | + aria-label="{{ 'item.selected' | translate }}" | ||
57 | + ng-checked="vm.isRuleChainSelected(ruleChain)"></md-checkbox> | ||
58 | + <span> {{ ruleChain.name }} </span> | ||
59 | + </md-list-item> | ||
60 | + </md-list> | ||
61 | + </md-virtual-repeat-container> | ||
62 | + </div> | ||
63 | + </fieldset> | ||
64 | + </div> | ||
65 | + </md-dialog-content> | ||
66 | + <md-dialog-actions layout="row"> | ||
67 | + <span flex></span> | ||
68 | + <md-button ng-disabled="$root.loading || vm.ruleChains.selection==null" type="submit" class="md-raised md-primary"> | ||
69 | + {{ 'action.assign' | translate }} | ||
70 | + </md-button> | ||
71 | + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | | ||
72 | + translate }} | ||
73 | + </md-button> | ||
74 | + </md-dialog-actions> | ||
75 | + </form> | ||
76 | +</md-dialog> |
@@ -792,6 +792,7 @@ | @@ -792,6 +792,7 @@ | ||
792 | "dashboards": "Edge Dashboards", | 792 | "dashboards": "Edge Dashboards", |
793 | "manage-edge-rulechains": "Manage edge rule chains", | 793 | "manage-edge-rulechains": "Manage edge rule chains", |
794 | "rulechains": "Edge Rule Chains", | 794 | "rulechains": "Edge Rule Chains", |
795 | + "rulechain": "Edge Rule Chain", | ||
795 | "edge-key": "Edge key", | 796 | "edge-key": "Edge key", |
796 | "copy-edge-key": "Copy edge key", | 797 | "copy-edge-key": "Copy edge key", |
797 | "edge-key-copied-message": "Edge key has been copied to clipboard", | 798 | "edge-key-copied-message": "Edge key has been copied to clipboard", |
@@ -803,7 +804,10 @@ | @@ -803,7 +804,10 @@ | ||
803 | "manage-edge-entity-views": "Manage edge entity views", | 804 | "manage-edge-entity-views": "Manage edge entity views", |
804 | "assets": "Edge assets", | 805 | "assets": "Edge assets", |
805 | "devices": "Edge devices", | 806 | "devices": "Edge devices", |
806 | - "entity-views": "Edge entity views" | 807 | + "entity-views": "Edge entity views", |
808 | + "set-root-rule-chain-text": "Please select root rule chain for edge(s)", | ||
809 | + "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)", | ||
810 | + "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }" | ||
807 | }, | 811 | }, |
808 | "error": { | 812 | "error": { |
809 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", | 813 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", |
@@ -31,7 +31,7 @@ | @@ -31,7 +31,7 @@ | ||
31 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> | 31 | <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> |
32 | <md-dialog-content> | 32 | <md-dialog-content> |
33 | <div class="md-dialog-content"> | 33 | <div class="md-dialog-content"> |
34 | - <tb-rule-chain rule-chain="vm.item" is-edit="true" the-form="theForm"></tb-rule-chain> | 34 | + <tb-rule-chain rule-chain="vm.item" is-edit="true" rule-chain-scope="'tenant'" the-form="theForm"></tb-rule-chain> |
35 | </div> | 35 | </div> |
36 | </md-dialog-content> | 36 | </md-dialog-content> |
37 | <md-dialog-actions layout="row"> | 37 | <md-dialog-actions layout="row"> |
@@ -54,7 +54,7 @@ export default function AddRuleChainsToEdgeController(ruleChainService, $mdDialo | @@ -54,7 +54,7 @@ export default function AddRuleChainsToEdgeController(ruleChainService, $mdDialo | ||
54 | vm.ruleChains.pending = true; | 54 | vm.ruleChains.pending = true; |
55 | ruleChainService.getRuleChains(vm.ruleChains.nextPageLink).then( | 55 | ruleChainService.getRuleChains(vm.ruleChains.nextPageLink).then( |
56 | function success(ruleChains) { | 56 | function success(ruleChains) { |
57 | - vm.ruleChains.data = vm.ruleChains.data.concat(filterNonRootRuleChains(ruleChains.data)); | 57 | + vm.ruleChains.data = ruleChains.data; |
58 | vm.ruleChains.nextPageLink = ruleChains.nextPageLink; | 58 | vm.ruleChains.nextPageLink = ruleChains.nextPageLink; |
59 | vm.ruleChains.hasNext = ruleChains.hasNext; | 59 | vm.ruleChains.hasNext = ruleChains.hasNext; |
60 | if (vm.ruleChains.hasNext) { | 60 | if (vm.ruleChains.hasNext) { |
@@ -119,12 +119,4 @@ export default function AddRuleChainsToEdgeController(ruleChainService, $mdDialo | @@ -119,12 +119,4 @@ export default function AddRuleChainsToEdgeController(ruleChainService, $mdDialo | ||
119 | pending: false | 119 | pending: false |
120 | }; | 120 | }; |
121 | } | 121 | } |
122 | - | ||
123 | - function filterNonRootRuleChains(ruleChains) { | ||
124 | - return $filter('filter')(ruleChains, isNonRootRuleChain); | ||
125 | - } | ||
126 | - | ||
127 | - function isNonRootRuleChain(ruleChain) { | ||
128 | - return ruleChain && !ruleChain.root; | ||
129 | - } | ||
130 | } | 122 | } |
@@ -16,4 +16,4 @@ | @@ -16,4 +16,4 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | <div class="tb-small tb-rule-chain-assigned-edges" ng-show="vm.parentCtl.ruleChainsScope === 'tenant' && vm.item.assignedEdgesText">{{'rulechain.assigned-to-edges' | translate}}: '{{vm.item.assignedEdgesText}}'</div> | 18 | <div class="tb-small tb-rule-chain-assigned-edges" ng-show="vm.parentCtl.ruleChainsScope === 'tenant' && vm.item.assignedEdgesText">{{'rulechain.assigned-to-edges' | translate}}: '{{vm.item.assignedEdgesText}}'</div> |
19 | -<div ng-if="item && item.root" translate>rulechain.root</div> | 19 | +<div ng-if="(vm.parentCtl.ruleChainsScope === 'tenant' && item && item.root) || (vm.parentCtl.ruleChainsScope === 'edge' && vm.parentCtl.isRootRuleChain(item))" translate>rulechain.root</div> |
@@ -51,7 +51,7 @@ | @@ -51,7 +51,7 @@ | ||
51 | </md-input-container> | 51 | </md-input-container> |
52 | <md-input-container class="md-block"> | 52 | <md-input-container class="md-block"> |
53 | <label translate>rulechain.type</label> | 53 | <label translate>rulechain.type</label> |
54 | - <md-select ng-disabled="$root.loading || !isEdit" name="type" ng-model="ruleChain.type"> | 54 | + <md-select ng-disabled="$root.loading || !isEdit || ruleChainScope !== 'tenant' || ruleChain.root === true" name="type" ng-model="ruleChain.type"> |
55 | <md-option ng-repeat="ruleChainType in ruleChainTypes" value="{{ruleChainType}}"> | 55 | <md-option ng-repeat="ruleChainType in ruleChainTypes" value="{{ruleChainType}}"> |
56 | {{ruleChainType}} | 56 | {{ruleChainType}} |
57 | </md-option> | 57 | </md-option> |
@@ -49,7 +49,7 @@ export default function RuleChainDirective($compile, $templateCache, $mdDialog, | @@ -49,7 +49,7 @@ export default function RuleChainDirective($compile, $templateCache, $mdDialog, | ||
49 | theForm: '=', | 49 | theForm: '=', |
50 | onSetRootRuleChain: '&', | 50 | onSetRootRuleChain: '&', |
51 | onExportRuleChain: '&', | 51 | onExportRuleChain: '&', |
52 | - onDeleteRuleChain: '&', | 52 | + onDeleteRuleChain: '&' |
53 | } | 53 | } |
54 | }; | 54 | }; |
55 | } | 55 | } |
@@ -145,5 +145,43 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider | @@ -145,5 +145,43 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider | ||
145 | ncyBreadcrumb: { | 145 | ncyBreadcrumb: { |
146 | label: '{"icon": "settings_ethernet", "label": "{{ vm.edgeRuleChainsTitle }}", "translate": "false"}' | 146 | label: '{"icon": "settings_ethernet", "label": "{{ vm.edgeRuleChainsTitle }}", "translate": "false"}' |
147 | } | 147 | } |
148 | + }) | ||
149 | + .state('home.edges.ruleChains.ruleChain', { | ||
150 | + url: '/:ruleChainId', | ||
151 | + reloadOnSearch: false, | ||
152 | + module: 'private', | ||
153 | + auth: ['SYS_ADMIN', 'TENANT_ADMIN'], | ||
154 | + views: { | ||
155 | + "content@home": { | ||
156 | + templateUrl: ruleChainTemplate, | ||
157 | + controller: 'RuleChainController', | ||
158 | + controllerAs: 'vm' | ||
159 | + } | ||
160 | + }, | ||
161 | + resolve: { | ||
162 | + ruleChain: | ||
163 | + /*@ngInject*/ | ||
164 | + function($stateParams, ruleChainService) { | ||
165 | + return ruleChainService.getRuleChain($stateParams.ruleChainId); | ||
166 | + }, | ||
167 | + ruleChainMetaData: | ||
168 | + /*@ngInject*/ | ||
169 | + function($stateParams, ruleChainService) { | ||
170 | + return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId); | ||
171 | + }, | ||
172 | + ruleNodeComponents: | ||
173 | + /*@ngInject*/ | ||
174 | + function($stateParams, ruleChainService) { | ||
175 | + return ruleChainService.getRuleNodeComponents(); | ||
176 | + } | ||
177 | + }, | ||
178 | + data: { | ||
179 | + import: false, | ||
180 | + searchEnabled: false, | ||
181 | + pageTitle: 'edge.rulechain' | ||
182 | + }, | ||
183 | + ncyBreadcrumb: { | ||
184 | + label: '{"icon": "settings_ethernet", "label": "edge.rulechain"}' | ||
185 | + } | ||
148 | }); | 186 | }); |
149 | } | 187 | } |
@@ -25,7 +25,7 @@ import addRuleChainsToEdgeTemplate from "./add-rulechains-to-edge.tpl.html"; | @@ -25,7 +25,7 @@ import addRuleChainsToEdgeTemplate from "./add-rulechains-to-edge.tpl.html"; | ||
25 | import './rulechain-card.scss'; | 25 | import './rulechain-card.scss'; |
26 | 26 | ||
27 | /*@ngInject*/ | 27 | /*@ngInject*/ |
28 | -export default function RuleChainsController(ruleChainService, userService, importExport, $state, | 28 | +export default function RuleChainsController(ruleChainService, userService, edgeService, importExport, $state, |
29 | $stateParams, $filter, $translate, $mdDialog, $document, $q, types) { | 29 | $stateParams, $filter, $translate, $mdDialog, $document, $q, types) { |
30 | 30 | ||
31 | var vm = this; | 31 | var vm = this; |
@@ -107,6 +107,11 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -107,6 +107,11 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
107 | 107 | ||
108 | if (edgeId) { | 108 | if (edgeId) { |
109 | vm.edgeRuleChainsTitle = $translate.instant('edge.rulechains'); | 109 | vm.edgeRuleChainsTitle = $translate.instant('edge.rulechains'); |
110 | + edgeService.getEdge(edgeId).then( | ||
111 | + function success(edge) { | ||
112 | + vm.edge = edge; | ||
113 | + } | ||
114 | + ); | ||
110 | } | 115 | } |
111 | 116 | ||
112 | if (vm.ruleChainsScope === 'tenant') { | 117 | if (vm.ruleChainsScope === 'tenant') { |
@@ -133,8 +138,7 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -133,8 +138,7 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
133 | }, | 138 | }, |
134 | name: function() { return $translate.instant('action.assign') }, | 139 | name: function() { return $translate.instant('action.assign') }, |
135 | details: function() { return $translate.instant('rulechain.manage-assigned-edges') }, | 140 | details: function() { return $translate.instant('rulechain.manage-assigned-edges') }, |
136 | - icon: "wifi_tethering", | ||
137 | - isEnabled: isNonRootRuleChain | 141 | + icon: "wifi_tethering" |
138 | }); | 142 | }); |
139 | 143 | ||
140 | ruleChainActionsList.push({ | 144 | ruleChainActionsList.push({ |
@@ -214,6 +218,16 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -214,6 +218,16 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
214 | return ruleChainService.unassignRuleChainFromEdge(edgeId, ruleChainId); | 218 | return ruleChainService.unassignRuleChainFromEdge(edgeId, ruleChainId); |
215 | }; | 219 | }; |
216 | 220 | ||
221 | + ruleChainActionsList.push({ | ||
222 | + onAction: function ($event, item) { | ||
223 | + setRootRuleChain($event, item); | ||
224 | + }, | ||
225 | + name: function() { return $translate.instant('rulechain.set-root') }, | ||
226 | + details: function() { return $translate.instant('rulechain.set-root') }, | ||
227 | + icon: "flag", | ||
228 | + isEnabled: isNonRootRuleChain | ||
229 | + }); | ||
230 | + | ||
217 | ruleChainActionsList.push( | 231 | ruleChainActionsList.push( |
218 | { | 232 | { |
219 | onAction: function ($event, item) { | 233 | onAction: function ($event, item) { |
@@ -221,7 +235,8 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -221,7 +235,8 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
221 | }, | 235 | }, |
222 | name: function() { return $translate.instant('action.unassign') }, | 236 | name: function() { return $translate.instant('action.unassign') }, |
223 | details: function() { return $translate.instant('rulechain.unassign-from-edge') }, | 237 | details: function() { return $translate.instant('rulechain.unassign-from-edge') }, |
224 | - icon: "assignment_return" | 238 | + icon: "assignment_return", |
239 | + isEnabled: isNonRootRuleChain | ||
225 | } | 240 | } |
226 | ); | 241 | ); |
227 | 242 | ||
@@ -288,7 +303,13 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -288,7 +303,13 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
288 | if ($event) { | 303 | if ($event) { |
289 | $event.stopPropagation(); | 304 | $event.stopPropagation(); |
290 | } | 305 | } |
291 | - $state.go('home.ruleChains.ruleChain', {ruleChainId: ruleChain.id.id}); | 306 | + if (vm.ruleChainsScope === 'edge') { |
307 | + $state.go('home.edges.ruleChains.ruleChain', { | ||
308 | + ruleChainId: ruleChain.id.id | ||
309 | + }); | ||
310 | + } else { | ||
311 | + $state.go('home.ruleChains.ruleChain', {ruleChainId: ruleChain.id.id}); | ||
312 | + } | ||
292 | } | 313 | } |
293 | 314 | ||
294 | function deleteRuleChain(ruleChainId) { | 315 | function deleteRuleChain(ruleChainId) { |
@@ -300,11 +321,19 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -300,11 +321,19 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
300 | } | 321 | } |
301 | 322 | ||
302 | function isRootRuleChain(ruleChain) { | 323 | function isRootRuleChain(ruleChain) { |
303 | - return ruleChain && ruleChain.root; | 324 | + if (angular.isDefined(vm.edge) && vm.edge != null) { |
325 | + return angular.isDefined(vm.edge.rootRuleChainId) && vm.edge.rootRuleChainId != null && vm.edge.rootRuleChainId.id === ruleChain.id.id; | ||
326 | + } else { | ||
327 | + return ruleChain && ruleChain.root; | ||
328 | + } | ||
304 | } | 329 | } |
305 | 330 | ||
306 | function isNonRootRuleChain(ruleChain) { | 331 | function isNonRootRuleChain(ruleChain) { |
307 | - return ruleChain && !ruleChain.root; | 332 | + if (angular.isDefined(vm.edge) && vm.edge != null) { |
333 | + return angular.isDefined(vm.edge.rootRuleChainId) && vm.edge.rootRuleChainId != null && vm.edge.rootRuleChainId.id !== ruleChain.id.id; | ||
334 | + } else { | ||
335 | + return ruleChain && !ruleChain.root; | ||
336 | + } | ||
308 | } | 337 | } |
309 | 338 | ||
310 | function exportRuleChain($event, ruleChain) { | 339 | function exportRuleChain($event, ruleChain) { |
@@ -322,11 +351,20 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -322,11 +351,20 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
322 | .cancel($translate.instant('action.no')) | 351 | .cancel($translate.instant('action.no')) |
323 | .ok($translate.instant('action.yes')); | 352 | .ok($translate.instant('action.yes')); |
324 | $mdDialog.show(confirm).then(function () { | 353 | $mdDialog.show(confirm).then(function () { |
325 | - ruleChainService.setRootRuleChain(ruleChain.id.id).then( | ||
326 | - () => { | ||
327 | - vm.grid.refreshList(); | ||
328 | - } | ||
329 | - ); | 354 | + if (angular.isDefined(vm.edge) && vm.edge != null) { |
355 | + edgeService.setRootRuleChain(vm.edge.id.id, ruleChain.id.id).then( | ||
356 | + (edge) => { | ||
357 | + vm.edge = edge; | ||
358 | + vm.grid.refreshList(); | ||
359 | + } | ||
360 | + ); | ||
361 | + } else { | ||
362 | + ruleChainService.setRootRuleChain(ruleChain.id.id).then( | ||
363 | + () => { | ||
364 | + vm.grid.refreshList(); | ||
365 | + } | ||
366 | + ); | ||
367 | + } | ||
330 | }); | 368 | }); |
331 | } | 369 | } |
332 | 370 | ||
@@ -396,7 +434,7 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -396,7 +434,7 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
396 | function success(_ruleChains) { | 434 | function success(_ruleChains) { |
397 | var ruleChains = { | 435 | var ruleChains = { |
398 | pageSize: pageSize, | 436 | pageSize: pageSize, |
399 | - data: filterNonRootRuleChains(_ruleChains.data), | 437 | + data: _ruleChains.data, |
400 | nextPageLink: _ruleChains.nextPageLink, | 438 | nextPageLink: _ruleChains.nextPageLink, |
401 | selections: {}, | 439 | selections: {}, |
402 | selectedCount: 0, | 440 | selectedCount: 0, |
@@ -423,10 +461,6 @@ export default function RuleChainsController(ruleChainService, userService, impo | @@ -423,10 +461,6 @@ export default function RuleChainsController(ruleChainService, userService, impo | ||
423 | }); | 461 | }); |
424 | } | 462 | } |
425 | 463 | ||
426 | - function filterNonRootRuleChains(ruleChains) { | ||
427 | - return $filter('filter')(ruleChains, isNonRootRuleChain); | ||
428 | - } | ||
429 | - | ||
430 | function unassignFromEdge($event, ruleChain, edgeId) { | 464 | function unassignFromEdge($event, ruleChain, edgeId) { |
431 | if ($event) { | 465 | if ($event) { |
432 | $event.stopPropagation(); | 466 | $event.stopPropagation(); |