Add External Rule Node types. Rule Chain UI improvements.
This commit is contained in:
parent
5e88b02f1e
commit
e7ae82b104
@ -118,6 +118,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
|
||||
case FILTER:
|
||||
case TRANSFORMATION:
|
||||
case ACTION:
|
||||
case EXTERNAL:
|
||||
RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class);
|
||||
scannedComponent.setName(ruleNodeAnnotation.name());
|
||||
scannedComponent.setScope(ruleNodeAnnotation.scope());
|
||||
@ -194,6 +195,8 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
|
||||
nodeDefinition.setDefaultConfiguration(mapper.valueToTree(defaultConfiguration));
|
||||
nodeDefinition.setUiResources(nodeAnnotation.uiResources());
|
||||
nodeDefinition.setConfigDirective(nodeAnnotation.configDirective());
|
||||
nodeDefinition.setIcon(nodeAnnotation.icon());
|
||||
nodeDefinition.setIconUrl(nodeAnnotation.iconUrl());
|
||||
return nodeDefinition;
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,6 @@ package org.thingsboard.server.common.data.plugin;
|
||||
*/
|
||||
public enum ComponentType {
|
||||
|
||||
ENRICHMENT, FILTER, TRANSFORMATION, ACTION, OLD_ACTION, PLUGIN
|
||||
ENRICHMENT, FILTER, TRANSFORMATION, ACTION, EXTERNAL, OLD_ACTION, PLUGIN
|
||||
|
||||
}
|
||||
|
||||
@ -31,5 +31,7 @@ public class NodeDefinition {
|
||||
JsonNode defaultConfiguration;
|
||||
String[] uiResources;
|
||||
String configDirective;
|
||||
String icon;
|
||||
String iconUrl;
|
||||
|
||||
}
|
||||
|
||||
@ -49,6 +49,10 @@ public @interface RuleNode {
|
||||
|
||||
String configDirective() default "";
|
||||
|
||||
String icon() default "";
|
||||
|
||||
String iconUrl() default "";
|
||||
|
||||
boolean customRelations() default false;
|
||||
|
||||
}
|
||||
|
||||
@ -47,7 +47,9 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
||||
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeAlarmConfig")
|
||||
configDirective = "tbActionNodeAlarmConfig",
|
||||
icon = "notifications_active"
|
||||
)
|
||||
|
||||
public class TbAlarmNode implements TbNode {
|
||||
|
||||
|
||||
@ -33,7 +33,9 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
||||
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeLogConfig")
|
||||
configDirective = "tbActionNodeLogConfig",
|
||||
icon = "menu"
|
||||
)
|
||||
|
||||
public class TbLogNode implements TbNode {
|
||||
|
||||
|
||||
@ -38,13 +38,14 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "aws sns",
|
||||
configClazz = TbSnsNodeConfiguration.class,
|
||||
nodeDescription = "Publish messages to AWS SNS",
|
||||
nodeDetails = "Expects messages with any message type. Will publish message to AWS SNS topic.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeSnsConfig"
|
||||
configDirective = "tbActionNodeSnsConfig",
|
||||
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
|
||||
)
|
||||
public class TbSnsNode implements TbNode {
|
||||
|
||||
|
||||
@ -41,13 +41,14 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "aws sqs",
|
||||
configClazz = TbSqsNodeConfiguration.class,
|
||||
nodeDescription = "Publish messages to AWS SQS",
|
||||
nodeDetails = "Expects messages with any message type. Will publish message to AWS SQS queue.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeSqsConfig"
|
||||
configDirective = "tbActionNodeSqsConfig",
|
||||
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
|
||||
)
|
||||
public class TbSqsNode implements TbNode {
|
||||
|
||||
|
||||
@ -40,7 +40,8 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
nodeDetails = "Generates messages with configurable period. ",
|
||||
inEnabled = false,
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
|
||||
configDirective = "tbActionNodeGeneratorConfig"
|
||||
configDirective = "tbActionNodeGeneratorConfig",
|
||||
icon = "repeat"
|
||||
)
|
||||
|
||||
public class TbMsgGeneratorNode implements TbNode {
|
||||
|
||||
@ -28,13 +28,14 @@ import java.util.concurrent.ExecutionException;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "kafka",
|
||||
configClazz = TbKafkaNodeConfiguration.class,
|
||||
nodeDescription = "Publish messages to Kafka server",
|
||||
nodeDetails = "Expects messages with any message type. Will send record via Kafka producer to Kafka server.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeKafkaConfig"
|
||||
configDirective = "tbActionNodeKafkaConfig",
|
||||
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg=="
|
||||
)
|
||||
public class TbKafkaNode implements TbNode {
|
||||
|
||||
|
||||
@ -38,7 +38,9 @@ import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
|
||||
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
||||
"If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbTransformationNodeToEmailConfig")
|
||||
configDirective = "tbTransformationNodeToEmailConfig",
|
||||
icon = "email"
|
||||
)
|
||||
public class TbMsgToEmailNode implements TbNode {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
||||
@ -35,7 +35,7 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "send email",
|
||||
configClazz = TbSendEmailNodeConfiguration.class,
|
||||
nodeDescription = "Log incoming messages using JS script for transformation Message into String",
|
||||
@ -43,7 +43,8 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
||||
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeSendEmailConfig"
|
||||
configDirective = "tbActionNodeSendEmailConfig",
|
||||
icon = "send"
|
||||
)
|
||||
public class TbSendEmailNode implements TbNode {
|
||||
|
||||
|
||||
@ -43,13 +43,14 @@ import java.util.concurrent.TimeoutException;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "mqtt",
|
||||
configClazz = TbMqttNodeConfiguration.class,
|
||||
nodeDescription = "Publish messages to MQTT broker",
|
||||
nodeDetails = "Expects messages with any message type. Will publish message to MQTT broker.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
|
||||
configDirective = "tbActionNodeMqttConfig"
|
||||
configDirective = "tbActionNodeMqttConfig",
|
||||
icon = "call_split"
|
||||
)
|
||||
public class TbMqttNode implements TbNode {
|
||||
|
||||
|
||||
@ -33,13 +33,14 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "rabbitmq",
|
||||
configClazz = TbRabbitMqNodeConfiguration.class,
|
||||
nodeDescription = "Publish messages to RabbitMQ",
|
||||
nodeDetails = "Expects messages with any message type. Will publish message to RabbitMQ queue.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeRabbitMqConfig"
|
||||
configDirective = "tbActionNodeRabbitMqConfig",
|
||||
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4="
|
||||
)
|
||||
public class TbRabbitMqNode implements TbNode {
|
||||
|
||||
|
||||
@ -26,7 +26,8 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.Netty4ClientHttpRequestFactory;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.web.client.*;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.thingsboard.rule.engine.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.api.*;
|
||||
import org.thingsboard.server.common.data.plugin.ComponentType;
|
||||
@ -34,19 +35,19 @@ import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
type = ComponentType.EXTERNAL,
|
||||
name = "rest api call",
|
||||
configClazz = TbRestApiCallNodeConfiguration.class,
|
||||
nodeDescription = "Invoke REST API calls to external REST server",
|
||||
nodeDetails = "Expects messages with any message type. Will invoke REST API call to external REST server.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeRestApiCallConfig"
|
||||
configDirective = "tbActionNodeRestApiCallConfig",
|
||||
iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+"
|
||||
)
|
||||
public class TbRestApiCallNode implements TbNode {
|
||||
|
||||
|
||||
@ -36,7 +36,8 @@ import org.thingsboard.server.common.msg.TbMsg;
|
||||
nodeDescription = "Sends reply to the RPC call from device",
|
||||
nodeDetails = "Expects messages with any message type. Will forward message body to the device.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeRpcReplyConfig"
|
||||
configDirective = "tbActionNodeRpcReplyConfig",
|
||||
icon = "call_merge"
|
||||
)
|
||||
public class TbSendRPCReplyNode implements TbNode {
|
||||
|
||||
|
||||
@ -43,7 +43,8 @@ import java.util.concurrent.TimeUnit;
|
||||
nodeDescription = "Sends one-way RPC call to device",
|
||||
nodeDetails = "Expects messages with \"method\" and \"params\". Will forward response from device to next nodes.",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||
configDirective = "tbActionNodeRpcRequestConfig"
|
||||
configDirective = "tbActionNodeRpcRequestConfig",
|
||||
icon = "call_made"
|
||||
)
|
||||
public class TbSendRPCRequestNode implements TbNode {
|
||||
|
||||
|
||||
@ -48,7 +48,8 @@ import java.util.Set;
|
||||
nodeDescription = "Saves attributes data",
|
||||
nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
|
||||
configDirective = "tbActionNodeAttributesConfig"
|
||||
configDirective = "tbActionNodeAttributesConfig",
|
||||
icon = "file_upload"
|
||||
)
|
||||
public class TbMsgAttributesNode implements TbNode {
|
||||
|
||||
|
||||
@ -45,7 +45,8 @@ import java.util.Map;
|
||||
nodeDescription = "Saves timeseries data",
|
||||
nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
|
||||
configDirective = "tbActionNodeTimeseriesConfig"
|
||||
configDirective = "tbActionNodeTimeseriesConfig",
|
||||
icon = "file_upload"
|
||||
)
|
||||
public class TbMsgTimeseriesNode implements TbNode {
|
||||
|
||||
|
||||
@ -40,7 +40,9 @@ import java.util.HashSet;
|
||||
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
||||
"If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ",
|
||||
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
|
||||
configDirective = "tbTransformationNodeChangeOriginatorConfig")
|
||||
configDirective = "tbTransformationNodeChangeOriginatorConfig",
|
||||
icon = "find_replace"
|
||||
)
|
||||
public class TbChangeOriginatorNode extends TbAbstractTransformNode {
|
||||
|
||||
protected static final String CUSTOMER_SOURCE = "CUSTOMER";
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -485,7 +485,7 @@ export default angular.module('thingsboard.types', [])
|
||||
clientSide: false
|
||||
}
|
||||
},
|
||||
ruleNodeTypeComponentTypes: ["FILTER", "ENRICHMENT", "TRANSFORMATION", "ACTION"],
|
||||
ruleNodeTypeComponentTypes: ["FILTER", "ENRICHMENT", "TRANSFORMATION", "ACTION", "EXTERNAL"],
|
||||
ruleChainNodeComponent: {
|
||||
type: 'RULE_CHAIN',
|
||||
name: 'rule chain',
|
||||
@ -536,6 +536,13 @@ export default angular.module('thingsboard.types', [])
|
||||
nodeClass: "tb-action-type",
|
||||
icon: "flash_on"
|
||||
},
|
||||
EXTERNAL: {
|
||||
value: "EXTERNAL",
|
||||
name: "rulenode.type-external",
|
||||
details: "rulenode.type-external-details",
|
||||
nodeClass: "tb-external-type",
|
||||
icon: "cloud_upload"
|
||||
},
|
||||
RULE_CHAIN: {
|
||||
value: "RULE_CHAIN",
|
||||
name: "rulenode.type-rule-chain",
|
||||
|
||||
@ -1228,6 +1228,8 @@ export default angular.module('thingsboard.locale', [])
|
||||
"type-transformation-details": "Change Message payload and Metadata",
|
||||
"type-action": "Action",
|
||||
"type-action-details": "Perform special action",
|
||||
"type-external": "External",
|
||||
"type-external-details": "Interacts with external system",
|
||||
"type-rule-chain": "Rule Chain",
|
||||
"type-rule-chain-details": "Forwards incoming messages to specified Rule Chain",
|
||||
"directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.",
|
||||
|
||||
@ -246,6 +246,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
||||
var contextInfo = {
|
||||
headerClass: node.nodeClass,
|
||||
icon: node.icon,
|
||||
iconUrl: node.iconUrl,
|
||||
title: node.name,
|
||||
subtitle: node.component.name
|
||||
};
|
||||
@ -805,12 +806,21 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
||||
var ruleNodeComponent = ruleNodeComponents[i];
|
||||
componentType = ruleNodeComponent.type;
|
||||
var model = vm.ruleNodeTypesModel[componentType].model;
|
||||
var icon = vm.types.ruleNodeType[componentType].icon;
|
||||
var iconUrl = null;
|
||||
if (ruleNodeComponent.configurationDescriptor.nodeDefinition.icon) {
|
||||
icon = ruleNodeComponent.configurationDescriptor.nodeDefinition.icon;
|
||||
}
|
||||
if (ruleNodeComponent.configurationDescriptor.nodeDefinition.iconUrl) {
|
||||
iconUrl = ruleNodeComponent.configurationDescriptor.nodeDefinition.iconUrl;
|
||||
}
|
||||
var node = {
|
||||
id: 'node-lib-' + componentType + '-' + model.nodes.length,
|
||||
component: ruleNodeComponent,
|
||||
name: '',
|
||||
nodeClass: vm.types.ruleNodeType[componentType].nodeClass,
|
||||
icon: vm.types.ruleNodeType[componentType].icon,
|
||||
icon: icon,
|
||||
iconUrl: iconUrl,
|
||||
x: 30,
|
||||
y: 10+50*model.nodes.length,
|
||||
connectors: []
|
||||
@ -904,6 +914,14 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
||||
var ruleNode = vm.ruleChainMetaData.nodes[i];
|
||||
var component = ruleChainService.getRuleNodeComponentByClazz(ruleNode.type);
|
||||
if (component) {
|
||||
var icon = vm.types.ruleNodeType[component.type].icon;
|
||||
var iconUrl = null;
|
||||
if (component.configurationDescriptor.nodeDefinition.icon) {
|
||||
icon = component.configurationDescriptor.nodeDefinition.icon;
|
||||
}
|
||||
if (component.configurationDescriptor.nodeDefinition.iconUrl) {
|
||||
iconUrl = component.configurationDescriptor.nodeDefinition.iconUrl;
|
||||
}
|
||||
var node = {
|
||||
id: 'rule-chain-node-' + vm.nextNodeID++,
|
||||
ruleNodeId: ruleNode.id,
|
||||
@ -915,7 +933,8 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
||||
component: component,
|
||||
name: ruleNode.name,
|
||||
nodeClass: vm.types.ruleNodeType[component.type].nodeClass,
|
||||
icon: vm.types.ruleNodeType[component.type].icon,
|
||||
icon: icon,
|
||||
iconUrl: iconUrl,
|
||||
connectors: []
|
||||
};
|
||||
if (component.configurationDescriptor.nodeDefinition.inEnabled) {
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
min-width: 180px;
|
||||
min-width: 150px;
|
||||
}
|
||||
.fc-canvas {
|
||||
background: #f9f9f9;
|
||||
@ -161,6 +161,9 @@
|
||||
&.tb-action-type {
|
||||
background-color: #f1928f;
|
||||
}
|
||||
&.tb-external-type {
|
||||
background-color: #fbc766;
|
||||
}
|
||||
&.tb-rule-chain-type {
|
||||
background-color: #d6c4f1;
|
||||
}
|
||||
|
||||
@ -75,6 +75,8 @@
|
||||
<md-expansion-panel md-component-id="{{typeId}}" id="{{typeId}}" ng-repeat="(typeId, typeModel) in vm.ruleNodeTypesModel">
|
||||
<md-expansion-panel-collapsed ng-mouseenter="vm.typeHeaderMouseEnter($event, typeId)"
|
||||
ng-mouseleave="vm.destroyTooltips()">
|
||||
<md-icon aria-label="node-type-icon"
|
||||
class="material-icons" style="margin-right: 8px;">{{vm.types.ruleNodeType[typeId].icon}}</md-icon>
|
||||
<div class="tb-panel-title" translate>{{vm.types.ruleNodeType[typeId].name}}</div>
|
||||
<md-expansion-panel-icon></md-expansion-panel-icon>
|
||||
</md-expansion-panel-collapsed>
|
||||
@ -82,6 +84,8 @@
|
||||
<md-expansion-panel-header ng-mouseenter="vm.typeHeaderMouseEnter($event, typeId)"
|
||||
ng-mouseleave="vm.destroyTooltips()"
|
||||
ng-click="vm.$mdExpansionPanel(typeId).collapse()">
|
||||
<md-icon aria-label="node-type-icon"
|
||||
class="material-icons" style="margin-right: 8px;">{{vm.types.ruleNodeType[typeId].icon}}</md-icon>
|
||||
<div class="tb-panel-title" translate>{{vm.types.ruleNodeType[typeId].name}}</div>
|
||||
<md-expansion-panel-icon></md-expansion-panel-icon>
|
||||
</md-expansion-panel-header>
|
||||
@ -114,8 +118,10 @@
|
||||
</div>
|
||||
<md-menu-content id="tb-rule-chain-context-menu" width="4" ng-mouseleave="$mdCloseMousepointMenu()">
|
||||
<div class="tb-context-menu-header {{vm.contextInfo.headerClass}}">
|
||||
<md-icon aria-label="node-type-icon"
|
||||
<md-icon ng-if="!vm.contextInfo.iconUrl" aria-label="node-type-icon"
|
||||
class="material-icons">{{vm.contextInfo.icon}}</md-icon>
|
||||
<md-icon ng-if="vm.contextInfo.iconUrl" aria-label="node-type-icon"
|
||||
md-svg-icon="{{vm.contextInfo.iconUrl}}"></md-icon>
|
||||
<div flex>
|
||||
<div class="tb-context-menu-title">{{vm.contextInfo.title}}</div>
|
||||
<div class="tb-context-menu-subtitle">{{vm.contextInfo.subtitle}}</div>
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
ng-mouseleave="callbacks.mouseLeave($event, node)">
|
||||
<div class="{{flowchartConstants.nodeOverlayClass}}"></div>
|
||||
<div class="tb-rule-node {{node.nodeClass}}" ng-class="{'tb-rule-node-highlighted' : node.highlighted, 'tb-rule-node-invalid': node.error }">
|
||||
<md-icon aria-label="node-type-icon" flex="15"
|
||||
<md-icon ng-if="!node.iconUrl" aria-label="node-type-icon" flex="15"
|
||||
class="material-icons">{{node.icon}}</md-icon>
|
||||
<md-icon ng-if="node.iconUrl" aria-label="node-type-icon" flex="15"
|
||||
md-svg-icon="{{node.iconUrl}}"></md-icon>
|
||||
<div layout="column" flex="85" layout-align="center">
|
||||
<span class="tb-node-type">{{ node.component.name }}</span>
|
||||
<span class="tb-node-title" ng-if="node.name">{{ node.name }}</span>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user