From a42bd5d7eeaf744aa58df15d5b943a3b7cc36d1a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 23 Dec 2019 14:36:44 +0200 Subject: [PATCH] UI: RuleNode configuration --- .../rule/engine/debug/TbMsgGeneratorNode.java | 2 +- .../engine/filter/TbMsgTypeFilterNode.java | 2 +- .../filter/TbOriginatorTypeFilterNode.java | 2 +- .../metadata/TbGetCustomerAttributeNode.java | 2 +- .../metadata/TbGetRelatedAttributeNode.java | 2 +- .../metadata/TbGetTenantAttributeNode.java | 2 +- .../rule/engine/mqtt/TbMqttNode.java | 2 +- .../engine/telemetry/TbMsgAttributesNode.java | 2 +- .../engine/telemetry/TbMsgTimeseriesNode.java | 2 +- .../transform/TbChangeOriginatorNode.java | 2 +- .../engine/transform/TbTransformMsgNode.java | 2 +- .../static/rulenode/rulenode-core-config.css | 2 - .../static/rulenode/rulenode-core-config.js | 22 +- ui-ngx/angular.json | 5 +- ui-ngx/package-lock.json | 5 + ui-ngx/package.json | 1 + ui-ngx/proxy.conf.js | 35 +++ ui-ngx/src/app/core/api/public-api.ts | 22 ++ ui-ngx/src/app/core/http/dashboard.service.ts | 1 + ui-ngx/src/app/core/http/public-api.ts | 34 +++ .../src/app/core/http/rule-chain.service.ts | 63 ++++-- .../local-storage/local-storage.service.ts | 1 + ui-ngx/src/app/core/public-api.ts | 23 ++ .../dialog/confirm-dialog.component.ts | 1 + ui-ngx/src/app/core/services/public-api.ts | 32 +++ ui-ngx/src/app/core/services/raf.service.ts | 1 + .../app/core/services/resources.service.ts | 52 ++++- .../script/node-script-test.service.ts | 31 +++ ui-ngx/src/app/core/services/utils.service.ts | 4 + ui-ngx/src/app/core/utils.ts | 9 + .../core/ws/telemetry-websocket.service.ts | 1 + .../alias/aliases-entity-select.component.ts | 1 + .../alias/entity-alias-dialog.component.ts | 2 +- .../alias/entity-alias-select.component.ts | 2 +- .../entity-aliases-dialog.component.html | 2 +- .../alias/entity-aliases-dialog.component.ts | 5 + .../attribute/attribute-table.component.html | 4 +- .../import-export/import-export.service.ts | 1 + .../app/modules/home/components/public-api.ts | 17 ++ .../relation/relation-filters.component.html | 8 +- .../relation/relation-filters.component.ts | 4 + .../custom-action-pretty-editor.component.ts | 3 + .../widget/data-key-config.component.ts | 2 +- .../components/widget/data-keys.component.ts | 2 +- .../widget/legend-config.component.html | 2 +- .../widget/legend-config.component.ts | 1 + .../widget/lib/flot-widget.models.ts | 10 +- .../home/components/widget/lib/flot-widget.ts | 15 +- .../widget/widget-component.service.ts | 5 +- .../widget/widget-config.component.html | 8 +- .../widget/widget-config.component.ts | 6 +- .../dashboard/dashboard-page.component.ts | 1 + .../dashboard/dashboard-routing.module.ts | 1 + .../entity-state-controller.component.ts | 2 +- .../src/app/modules/home/pages/public-api.ts | 17 ++ .../add-rule-node-dialog.component.html | 56 +++++ .../rulechain/link-labels.component.html | 2 +- .../pages/rulechain/link-labels.conponent.ts | 8 +- .../rulechain/rule-node-config.component.html | 28 +++ .../rulechain/rule-node-config.component.scss | 27 +++ .../rulechain/rule-node-config.component.ts | 208 ++++++++++++++++++ .../rule-node-details.component.html | 6 +- .../rulechain/rule-node-details.component.ts | 1 + .../rulechain/rulechain-page.component.ts | 101 ++++++++- .../rulechain/rulechain-routing.module.ts | 26 ++- .../home/pages/rulechain/rulechain.module.ts | 10 +- .../pages/user/add-user-dialog.component.html | 4 +- .../pages/user/add-user-dialog.component.ts | 2 +- .../pages/widget/widget-editor.component.ts | 1 + .../widget/widget-library-routing.module.ts | 1 + ui-ngx/src/app/modules/home/public-api.ts | 17 ++ .../dashboard-autocomplete.component.ts | 2 +- .../components/dashboard-select.component.ts | 1 + .../entity/entity-autocomplete.component.ts | 2 +- .../entity/entity-keys-list.component.ts | 2 +- .../entity/entity-list.component.ts | 2 +- .../entity-subtype-autocomplete.component.ts | 2 +- .../entity/entity-subtype-list.component.ts | 2 +- .../entity/entity-type-list.component.ts | 2 +- .../components/fab-toolbar.component.ts | 1 + .../json-form/json-form.component.ts | 4 +- .../json-form/react/json-form-ace-editor.tsx | 1 - .../json-form/react/json-form-color.tsx | 4 +- .../json-form/react/json-form-schema-form.tsx | 3 +- .../json-form/react/json-form.models.ts | 4 +- .../mat-chip-draggable.directive.ts | 2 +- .../src/app/shared/components/public-api.ts | 17 ++ .../relation-type-autocomplete.component.ts | 2 +- .../components/time/timewindow.component.html | 8 +- .../components/time/timewindow.component.ts | 1 + ui-ngx/src/app/shared/models/constants.ts | 1 + ui-ngx/src/app/shared/models/id/public-api.ts | 33 +++ .../src/app/shared/models/material.models.ts | 3 +- .../src/app/shared/models/page/public-api.ts | 19 ++ ui-ngx/src/app/shared/models/public-api.ts | 47 ++++ .../src/app/shared/models/rule-node.models.ts | 69 ++++-- ui-ngx/src/app/shared/models/user.model.ts | 4 +- .../src/app/shared/pipe/enum-to-array.pipe.ts | 2 +- .../app/shared/pipe/keyboard-shortcut.pipe.ts | 1 + ui-ngx/src/app/shared/pipe/public-api.ts | 22 ++ ui-ngx/src/app/shared/public-api.ts | 20 ++ 101 files changed, 1151 insertions(+), 118 deletions(-) delete mode 100644 rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css create mode 100644 ui-ngx/proxy.conf.js create mode 100644 ui-ngx/src/app/core/api/public-api.ts create mode 100644 ui-ngx/src/app/core/http/public-api.ts create mode 100644 ui-ngx/src/app/core/public-api.ts create mode 100644 ui-ngx/src/app/core/services/public-api.ts create mode 100644 ui-ngx/src/app/core/services/script/node-script-test.service.ts create mode 100644 ui-ngx/src/app/modules/home/components/public-api.ts create mode 100644 ui-ngx/src/app/modules/home/pages/public-api.ts create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.scss create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/public-api.ts create mode 100644 ui-ngx/src/app/shared/components/public-api.ts create mode 100644 ui-ngx/src/app/shared/models/id/public-api.ts create mode 100644 ui-ngx/src/app/shared/models/page/public-api.ts create mode 100644 ui-ngx/src/app/shared/models/public-api.ts create mode 100644 ui-ngx/src/app/shared/pipe/public-api.ts create mode 100644 ui-ngx/src/app/shared/public-api.ts diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index 478b0b4666..956241cb77 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -41,7 +41,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; nodeDescription = "Periodically generates messages", nodeDetails = "Generates messages with configurable period. Javascript function used for message generation.", inEnabled = false, - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeGeneratorConfig", icon = "repeat" ) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java index 1873f0f29a..4717a482e3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.msg.TbMsg; relationTypes = {"True", "False"}, nodeDescription = "Filter incoming messages by Message Type", nodeDetails = "If incoming MessageType is expected - send Message via True chain, otherwise False chain is used.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeMessageTypeConfig") public class TbMsgTypeFilterNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java index 974d130ce1..6b03210352 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java @@ -30,7 +30,7 @@ import org.thingsboard.server.common.msg.TbMsg; relationTypes = {"True", "False"}, nodeDescription = "Filter incoming messages by message Originator Type", nodeDetails = "If Originator Type of incoming message is expected - send Message via True chain, otherwise False chain is used.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeOriginatorTypeConfig") public class TbOriginatorTypeFilterNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index 993a55923d..6e24bd6ee3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; "If Latest Telemetry enrichment configured, latest telemetry added into metadata. " + "To access those attributes in other nodes this template can be used " + "metadata.temperature.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCustomerAttributesConfig") public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index a0fb3894e6..23bbd779de 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -34,7 +34,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; "If Latest Telemetry enrichment configured, latest telemetry added into metadata. " + "To access those attributes in other nodes this template can be used " + "metadata.temperature.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeRelatedAttributesConfig") public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index 4b3d5baff8..99f1967d3a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -34,7 +34,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; "If Latest Telemetry enrichment configured, latest telemetry added into metadata. " + "To access those attributes in other nodes this template can be used " + "metadata.temperature.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeTenantAttributesConfig") public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index dd17414b87..f02a660e8d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -47,7 +47,7 @@ import java.util.concurrent.TimeoutException; configClazz = TbMqttNodeConfiguration.class, nodeDescription = "Publish messages to the MQTT broker", nodeDetails = "Will publish message payload to the MQTT broker with QoS AT_LEAST_ONCE.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeMqttConfig", icon = "call_split" ) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java index 8d39b47958..35473d3880 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java @@ -42,7 +42,7 @@ import java.util.Set; configClazz = TbMsgAttributesNodeConfiguration.class, 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"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeAttributesConfig", icon = "file_upload" ) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 8607f93d22..f8468d028b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -43,7 +43,7 @@ import java.util.Map; configClazz = TbMsgTimeseriesNodeConfiguration.class, 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"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbActionNodeTimeseriesConfig", icon = "file_upload" ) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java index a00267a663..14ce9cb669 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java @@ -44,7 +44,7 @@ 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.
" + "Alarm Originator found only in case original Originator is Alarm entity.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbTransformationNodeChangeOriginatorConfig", icon = "find_replace" ) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java index 81c4483166..686db51da0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java @@ -33,7 +33,7 @@ import org.thingsboard.server.common.msg.TbMsg; "Should return the following structure:
" + "{ msg: new payload,
   metadata: new metadata,
   msgType: new msgType }

" + "All fields in resulting object are optional and will be taken from original message if not specified.", - uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, + uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbTransformationNodeScriptConfig") public class TbTransformMsgNode extends TbAbstractTransformNode { diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css deleted file mode 100644 index b5109b5f90..0000000000 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.css +++ /dev/null @@ -1,2 +0,0 @@ -.tb-message-type-autocomplete .tb-not-found{display:block;line-height:1.5;height:48px}.tb-message-type-autocomplete .tb-not-found .tb-no-entries{line-height:48px}.tb-message-type-autocomplete li{height:auto!important;white-space:normal!important}.tb-generator-config tb-json-content.tb-message-body,.tb-generator-config tb-json-object-edit.tb-metadata-json{height:200px;display:block}.tb-mqtt-config .tb-credentials-panel-group .tb-panel-title{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:90px}@media (min-width:960px){.tb-mqtt-config .tb-credentials-panel-group .tb-panel-title{min-width:180px}}.tb-mqtt-config .tb-credentials-panel-group .tb-panel-prompt{font-size:14px;color:rgba(0,0,0,.87);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tb-mqtt-config .tb-credentials-panel-group.disabled .tb-panel-prompt,.tb-mqtt-config .tb-credentials-panel-group.disabled .tb-panel-title{color:rgba(0,0,0,.38)}.tb-mqtt-config .tb-credentials-panel-group md-icon.md-expansion-panel-icon{margin-right:0}.tb-mqtt-config .tb-container{width:100%}.tb-mqtt-config .dropdown-messages .tb-error-message{padding:5px 0 0}.tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}.tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:rgba(0,0,0,.54);font-size:12px;font-weight:700;white-space:nowrap}.tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}.tb-kv-map-config .body .row{padding-top:5px;max-height:40px}.tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}.tb-kv-map-config .body md-input-container.cell{margin:0;max-height:40px}.tb-kv-map-config .body .md-button{margin:0} -/*# sourceMappingURL=rulenode-core-config.css.map*/ \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 0b8ad1cd05..6764e0e1b5 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1,6 +1,16 @@ -!function(e){function t(i){if(n[i])return n[i].exports;var a=n[i]={exports:{},id:i,loaded:!1};return e[i].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),i=e[t[0]];return function(e,t,a){i.apply(this,[e,t,a].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(101)},function(e,t){},1,1,1,1,function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
{{ 'tb.rulenode.create-customer-if-not-exists' | translate }}
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{scope.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
{{ 'tb.rulenode.use-message-alarm-data' | translate }}
tb.rulenode.alarm-type-required
tb.rulenode.entity-type-pattern-hint
{{ severity.name | translate}}
tb.rulenode.alarm-severity-required
{{ 'tb.rulenode.propagate' | translate }}
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-type-pattern-required
tb.rulenode.entity-type-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
{{ 'tb.rulenode.create-entity-if-not-exists' | translate }}
tb.rulenode.create-entity-if-not-exists-hint
{{ 'tb.rulenode.remove-current-relations' | translate }}
tb.rulenode.remove-current-relations-hint
{{ 'tb.rulenode.change-originator-to-related-entity' | translate }}
tb.rulenode.change-originator-to-related-entity-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
{{ 'tb.rulenode.delete-relation-to-specific-entity' | translate }}
tb.rulenode.delete-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.relation-type-pattern-required
tb.rulenode.relation-type-pattern-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
tb.rulenode.message-count-required
tb.rulenode.min-message-count-message
tb.rulenode.period-seconds-required
tb.rulenode.min-period-seconds-message
{{ 'tb.rulenode.test-generator-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
tb.rulenode.min-inside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.min-outside-duration-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
'},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.bootstrap-servers-required
tb.rulenode.min-retries-message
tb.rulenode.min-batch-size-bytes-message
tb.rulenode.min-linger-ms-message
tb.rulenode.min-buffer-memory-bytes-message
{{ ackValue }}
tb.rulenode.key-serializer-required
tb.rulenode.value-serializer-required
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-to-string-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.mqtt-topic-pattern-hint
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
tb.rulenode.connect-timeout-required
tb.rulenode.connect-timeout-range
tb.rulenode.connect-timeout-range
{{ \'tb.rulenode.clean-session\' | translate }} {{ \'tb.rulenode.enable-ssl\' | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{credentialsValue.name | translate}}
tb.rulenode.credentials-type-required
tb.rulenode.username-required
tb.rulenode.password-required
'},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"; -},function(e,t){e.exports='
{{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.period-in-seconds-pattern-required
tb.rulenode.period-in-seconds-pattern-hint
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
'},function(e,t){e.exports="
tb.rulenode.gcp-project-id-required
tb.rulenode.pubsub-topic-name-required
{{ 'action.remove' | translate }} close
tb.rulenode.message-attributes-hint
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }} {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}
tb.rulenode.headers-hint
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
tb.rulenode.custom-table-name-required
tb.rulenode.custom-table-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
'},function(e,t){e.exports='
{{\'tb.rulenode.entity-details-\'+item.toLowerCase() | translate}} tb.rulenode.no-entity-details-matching {{\'tb.rulenode.entity-details-\'+$chip.toLowerCase() | translate}} {{ \'tb.rulenode.add-to-metadata\' | translate }}
tb.rulenode.add-to-metadata-hint
'},function(e,t){e.exports='
{{ type }}
tb.rulenode.fetch-mode-hint
{{ type }}
tb.rulenode.order-by-hint
{{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}
tb.rulenode.use-metadata-interval-patterns-hint
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.start-interval-pattern-required
tb.rulenode.start-interval-pattern-hint
tb.rulenode.end-interval-pattern-required
tb.rulenode.end-interval-pattern-hint
'},function(e,t){e.exports='
{{ \'tb.rulenode.tell-failure-if-absent\' | translate }}
tb.rulenode.tell-failure-if-absent-hint
'},function(e,t){e.exports='
'; -},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},31,function(e,t){e.exports='
tb.rulenode.separator-hint
tb.rulenode.separator-hint
{{ \'tb.rulenode.check-all-keys\' | translate }}
tb.rulenode.check-all-keys-hint
'},function(e,t){e.exports="
{{ 'tb.rulenode.check-relation-to-specific-entity' | translate }}
tb.rulenode.check-relation-hint
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
tb.rulenode.latitude-key-name-required
tb.rulenode.longitude-key-name-required
{{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}
{{ type.name | translate}}
tb.rulenode.circle-center-latitude-required
tb.rulenode.circle-center-longitude-required
tb.rulenode.range-required
{{ type.name | translate}}
tb.rulenode.polygon-definition-required
tb.rulenode.polygon-definition-hint
'},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(6),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(7),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(8),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue},a.testDetailsBuildJs=function(e){var n=angular.copy(a.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],a.ruleNodeId).then(function(e){a.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(9),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(10),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(11),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n,i){var a=function(a,r,l,s){var d=o.default;r.html(d),a.types=n,a.originator=null,a.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(a.configuration)}),s.$render=function(){a.configuration=s.$viewValue,a.configuration.originatorId&&a.configuration.originatorType?a.originator={id:a.configuration.originatorId,entityType:a.configuration.originatorType}:a.originator=null,a.$watch("originator",function(e,t){angular.equals(e,t)||(a.originator?(s.$viewValue.originatorId=a.originator.id,s.$viewValue.originatorType=a.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},a.testScript=function(e){var n=angular.copy(a.configuration.jsScript);i.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],a.ruleNodeId).then(function(e){a.configuration.jsScript=e,s.$setDirty()})},e(r.contents())(a)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:a}}a.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(1);var r=n(12),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(13),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(74),r=i(a),o=n(52),l=i(o),s=n(57),d=i(s),u=n(54),c=i(u),m=n(53),g=i(m),p=n(61),f=i(p),b=n(68),v=i(b),y=n(69),h=i(y),q=n(67),$=i(q),x=n(60),k=i(x),T=n(72),C=i(T),w=n(73),M=i(w),N=n(66),_=i(N),S=n(62),E=i(S),F=n(71),P=i(F),A=n(64),V=i(A),I=n(63),j=i(I),O=n(51),D=i(O),R=n(75),K=i(R),L=n(56),U=i(L),z=n(55),B=i(z),H=n(70),G=i(H),Y=n(58),Q=i(Y),J=n(65),W=i(J);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",r.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",d.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",h.default).directive("tbActionNodeRestApiCallConfig",$.default).directive("tbActionNodeKafkaConfig",k.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",_.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",P.default).directive("tbActionNodeMsgDelayConfig",V.default).directive("tbActionNodeMsgCountConfig",j.default).directive("tbActionNodeAssignToCustomerConfig",D.default).directive("tbActionNodeUnAssignToCustomerConfig",K.default).directive("tbActionNodeDeleteRelationConfig",U.default).directive("tbActionNodeCreateRelationConfig",B.default).directive("tbActionNodeCustomTableConfig",G.default).directive("tbActionNodeGpsGeofencingConfig",Q.default).directive("tbActionNodePubSubConfig",W.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(14),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(15),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$mdExpansionPanel=t,i.ruleNodeTypes=n,i.credentialsTypeChanged=function(){var e=i.configuration.credentials.type;i.configuration.credentials={},i.configuration.credentials.type=e,i.updateValidity()},i.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){i.$apply(function(){if(n.target.result){l.$setDirty();var a=n.target.result;a&&a.length>0&&("caCert"==t&&(i.configuration.credentials.caCertFileName=e.name,i.configuration.credentials.caCert=a),"privateKey"==t&&(i.configuration.credentials.privateKeyFileName=e.name,i.configuration.credentials.privateKey=a),"Cert"==t&&(i.configuration.credentials.certFileName=e.name,i.configuration.credentials.cert=a)),i.updateValidity()}})},n.readAsText(e.file)},i.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(i.configuration.credentials.caCertFileName=null,i.configuration.credentials.caCert=null),"privateKey"==e&&(i.configuration.credentials.privateKeyFileName=null,i.configuration.credentials.privateKey=null),"Cert"==e&&(i.configuration.credentials.certFileName=null,i.configuration.credentials.cert=null),i.updateValidity()},i.updateValidity=function(){var e=!0,t=i.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:i}}a.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a,n(2);var r=n(16),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(17),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(18),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.serviceAccountFileAdded=function(e){var t=new FileReader;t.onload=function(t){n.$apply(function(){if(t.target.result){r.$setDirty();var i=t.target.result;i&&i.length>0&&(n.configuration.serviceAccountKeyFileName=e.name,n.configuration.serviceAccountKey=i),n.updateValidity()}})},t.readAsText(e.file)},n.clearServiceAccountFile=function(){r.$setDirty(),n.configuration.serviceAccountKeyFileName=null,n.configuration.serviceAccountKey=null,n.updateValidity()},n.updateValidity=function(){var e=!0,t=n.configuration;t.serviceAccountKeyFileName&&t.serviceAccountKey||(e=!1),r.$setValidity("SAKey",e)},n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(19),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(20),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(21),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(22),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(23),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(24),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly" -},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(25),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(26),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(27),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(28),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(29),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(30),o=i(r)},function(e,t){"use strict";function n(e){var t=function(t,n,i,a){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(31),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(32),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),n.entityDetailsList=[];for(var s in t.entityDetails){var d=s;n.entityDetailsList.push(d)}r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(33),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s);var d=186;i.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,d],i.ruleNodeTypes=n,i.aggPeriodTimeUnits={},i.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,i.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,i.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,i.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,i.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{},link:i}}a.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(34),o=i(r);n(3)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(83),r=i(a),o=n(84),l=i(o),s=n(79),d=i(s),u=n(85),c=i(u),m=n(78),g=i(m),p=n(86),f=i(p),b=n(81),v=i(b),y=n(80),h=i(y);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",r.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",d.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).directive("tbEnrichmentNodeEntityDetailsConfig",h.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(35),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(36),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(37),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(38),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(39),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(40),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(41),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(93),r=i(a),o=n(91),l=i(o),s=n(94),d=i(s),u=n(88),c=i(u),m=n(92),g=i(m),p=n(87),f=i(p),b=n(89),v=i(b);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",r.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",d.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).directive("tbFilterNodeCheckMessageConfig",f.default).directive("tbFilterNodeGpsGeofencingConfig",v.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),a.$setViewValue(e),d()}function d(){var e=!0;t.required&&!t.kvList.length&&(e=!1),a.$setValidity("kvMap",e)}var u=o.default;n.html(u),t.ngModelCtrl=a,t.removeKeyVal=r,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||a.$setViewValue(t.query)}),a.$render=function(){if(a.$viewValue){var e=a.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),d()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(46),o=i(r);n(5)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||r.$setViewValue(n.query)}),r.$render=function(){n.query=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(47),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){var n=function(n,i,a,r){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||r.$setViewValue(n.configuration)}),r.$render=function(){n.configuration=r.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}a.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(48),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(97),r=i(a),o=n(99),l=i(o),s=n(100),d=i(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",r.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",d.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t,n){var i=function(i,a,r,l){var s=o.default;a.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var a=angular.copy(i.configuration.jsScript);n.testNodeScript(e,a,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}a.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(49),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=function(t,n,i,a){var r=o.default;n.html(r),t.$watch("configuration",function(e,n){angular.equals(e,n)||a.$setViewValue(t.configuration)}),a.$render=function(){t.configuration=a.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}a.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(50),o=i(r)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(104),r=i(a),o=n(90),l=i(o),s=n(82),d=i(s),u=n(98),c=i(u),m=n(59),g=i(m),p=n(77),f=i(p),b=n(96),v=i(b),y=n(76),h=i(y),q=n(95),$=i(q),x=n(103),k=i(x);t.default=angular.module("thingsboard.ruleChain.config",[r.default,l.default,d.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",h.default).directive("tbKvMapConfig",$.default).config(k.default).name},function(e,t){"use strict";function n(e){var t={tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647'.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","latest-timeseries":"Latest timeseries","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"Certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.", -"start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e){(0,o.default)(e)}a.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var r=n(102),o=i(r)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"},ALARM_ORIGINATOR:{name:"tb.rulenode.originator-alarm-originator",value:"ALARM_ORIGINATOR"}},fetchModeType:["FIRST","LAST","ALL"],samplingOrder:["ASC","DESC"],httpRequestType:["GET","POST","PUT","DELETE"],entityDetails:{COUNTRY:{name:"tb.rulenode.entity-details-country",value:"COUNTRY"},STATE:{name:"tb.rulenode.entity-details-state",value:"STATE"},ZIP:{name:"tb.rulenode.entity-details-zip",value:"ZIP"},ADDRESS:{name:"tb.rulenode.entity-details-address",value:"ADDRESS"},ADDRESS2:{name:"tb.rulenode.entity-details-address2",value:"ADDRESS2"},PHONE:{name:"tb.rulenode.entity-details-phone",value:"PHONE"},EMAIL:{name:"tb.rulenode.entity-details-email",value:"EMAIL"},ADDITIONAL_INFO:{name:"tb.rulenode.entity-details-additional_info",value:"ADDITIONAL_INFO"}},sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},perimeterType:{CIRCLE:{name:"tb.rulenode.perimeter-circle",value:"CIRCLE"},POLYGON:{name:"tb.rulenode.perimeter-polygon",value:"POLYGON"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},rangeUnit:{METER:{value:"METER",name:"tb.rulenode.range-unit-meter"},KILOMETER:{value:"KILOMETER",name:"tb.rulenode.range-unit-kilometer"},FOOT:{value:"FOOT",name:"tb.rulenode.range-unit-foot"},MILE:{value:"MILE",name:"tb.rulenode.range-unit-mile"},NAUTICAL_MILE:{value:"NAUTICAL_MILE",name:"tb.rulenode.range-unit-nautical-mile"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); -//# sourceMappingURL=rulenode-core-config.js.map \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/core"),require("@angular/common"),require("@ngx-translate/core"),require("@shared/public-api"),require("@ngrx/store"),require("@angular/forms")):"function"==typeof define&&define.amd?define("rulenode-core-config",["exports","@angular/core","@angular/common","@ngx-translate/core","@shared/public-api","@ngrx/store","@angular/forms"],t):t((e=e||self)["rulenode-core-config"]={},e.ng.core,e.ng.common,e["ngx-translate"],e.shared,e["ngrx-store"],e.ng.forms)}(this,(function(e,t,r,i,a,n,s){"use strict"; +/*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */var o=function(e,t){return(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])})(e,t)};function u(e,t){function r(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}var d=function(e){function r(t){var r=e.call(this,t)||this;return r.store=t,r}return u(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.onConfigurationSet=function(e){},r.decorators=[{type:t.Component,args:[{selector:"tb-node-empty-config",template:"
"}]}],r.ctorParameters=function(){return[{type:n.Store}]},r}(a.RuleNodeConfigurationComponent);var l=function(e){function r(t,r){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.attributeScopes=Object.keys(a.AttributeScope),i.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,i}return u(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.onConfigurationSet=function(e){var t=this;this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[s.Validators.required]]}),this.attributesConfigForm.valueChanges.subscribe((function(e){t.attributesConfigForm.valid?t.notifyConfigurationUpdated(e):t.notifyConfigurationUpdated(null)}))},r.decorators=[{type:t.Component,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],r.ctorParameters=function(){return[{type:n.Store},{type:s.FormBuilder}]},r}(a.RuleNodeConfigurationComponent);var m=function(e){function r(t,r){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i}return u(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.onConfigurationSet=function(e){var t=this;this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[s.Validators.required,s.Validators.min(0)]]}),this.timeseriesConfigForm.valueChanges.subscribe((function(e){t.timeseriesConfigForm.valid?t.notifyConfigurationUpdated(e):t.notifyConfigurationUpdated(null)}))},r.decorators=[{type:t.Component,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n
\n'}]}],r.ctorParameters=function(){return[{type:n.Store},{type:s.FormBuilder}]},r}(a.RuleNodeConfigurationComponent);var c=function(){function e(){}return e.decorators=[{type:t.NgModule,args:[{declarations:[l,m],imports:[r.CommonModule,a.SharedModule],exports:[l,m]}]}],e}(),p=function(){function e(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647'.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","latest-timeseries":"Latest timeseries","data-keys":"Message data","metadata-keys":"Message metadata","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-hint":"Relation type pattern, use ${metaKeyName} to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use metadata period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds metadata pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","period-in-seconds-pattern-hint":"Period in seconds pattern, use ${metaKeyName} to substitute variables from metadata","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"Certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","check-all-keys":"Check that all selected keys are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'You should press "enter" to complete field input.',"entity-details":"Select entity details:","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"You should enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".'},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.decorators=[{type:t.NgModule,args:[{declarations:[d],imports:[r.CommonModule,a.SharedModule],exports:[c,d]}]}],e.ctorParameters=function(){return[{type:i.TranslateService}]},e}();e.RuleNodeCoreConfigModule=p,e.default=p,e.ɵa=d,e.ɵb=c,e.ɵc=l,e.ɵd=m,Object.defineProperty(e,"__esModule",{value:!0})})); +//# sourceMappingURL=rulenode-core-config.umd.min.js.map \ No newline at end of file diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index c68e36a90b..3a6fb4fdb6 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -78,7 +78,8 @@ "node_modules/ace-builds/src-min/snippets/css.js", "node_modules/ace-builds/src-min/snippets/json.js", "node_modules/ace-builds/src-min/snippets/java.js", - "node_modules/ace-builds/src-min/snippets/javascript.js" + "node_modules/ace-builds/src-min/snippets/javascript.js", + "node_modules/systemjs/dist/system.js" ], "es5BrowserSupport": true, "customWebpackConfig": { @@ -116,7 +117,7 @@ "builder": "@angular-builders/custom-webpack:dev-server", "options": { "browserTarget": "thingsboard:build", - "proxyConfig": "proxy.conf.json" + "proxyConfig": "proxy.conf.js" }, "configurations": { "production": { diff --git a/ui-ngx/package-lock.json b/ui-ngx/package-lock.json index c435a8bec2..1922bf20ed 100644 --- a/ui-ngx/package-lock.json +++ b/ui-ngx/package-lock.json @@ -12624,6 +12624,11 @@ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", "dev": true }, + "systemjs": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-0.21.5.tgz", + "integrity": "sha512-GWzZhN/x7Fsae2CYkz2GF7OgOS+YDgKulcgd5L1kTogZHMKDrPx5T8zI8I0y5RoU9Dx78Z7j1XMfuFa1thD84A==" + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", diff --git a/ui-ngx/package.json b/ui-ngx/package.json index db02a1ca6a..c952c89c51 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -74,6 +74,7 @@ "schema-inspector": "^1.6.8", "screenfull": "^5.0.0", "split.js": "^1.5.11", + "systemjs": "0.21.5", "tinycolor2": "^1.4.1", "tooltipster": "^4.2.7", "tslib": "^1.10.0", diff --git a/ui-ngx/proxy.conf.js b/ui-ngx/proxy.conf.js new file mode 100644 index 0000000000..6b45570da1 --- /dev/null +++ b/ui-ngx/proxy.conf.js @@ -0,0 +1,35 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const ruleNodeUiforwardHost = 'localhost'; +const ruleNodeUiforwardPort = 8080; + +const PROXY_CONFIG = { + '/api': { + 'target': 'http://localhost:8080', + 'secure': false + }, + '/static/rulenode': { + 'target': `http://${ruleNodeUiforwardHost}:${ruleNodeUiforwardPort}`, + 'secure': false + }, + '/api/ws': { + 'target': 'ws://localhost:8080', + 'ws': true + } +} + +module.exports = PROXY_CONFIG; diff --git a/ui-ngx/src/app/core/api/public-api.ts b/ui-ngx/src/app/core/api/public-api.ts new file mode 100644 index 0000000000..4726c8f670 --- /dev/null +++ b/ui-ngx/src/app/core/api/public-api.ts @@ -0,0 +1,22 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './alias-controller'; +export * from './data-aggregator'; +export * from './datasource.service'; +export * from './datasource-subcription'; +export * from './widget-api.models'; +export * from './widget-subscription'; diff --git a/ui-ngx/src/app/core/http/dashboard.service.ts b/ui-ngx/src/app/core/http/dashboard.service.ts index 96b714a1c1..ba45fed342 100644 --- a/ui-ngx/src/app/core/http/dashboard.service.ts +++ b/ui-ngx/src/app/core/http/dashboard.service.ts @@ -25,6 +25,7 @@ import {WINDOW} from '@core/services/window.service'; import { ActivationEnd, NavigationEnd, Router } from '@angular/router'; import { filter, map, publishReplay, refCount } from 'rxjs/operators'; +// @dynamic @Injectable({ providedIn: 'root' }) diff --git a/ui-ngx/src/app/core/http/public-api.ts b/ui-ngx/src/app/core/http/public-api.ts new file mode 100644 index 0000000000..998ef6ac52 --- /dev/null +++ b/ui-ngx/src/app/core/http/public-api.ts @@ -0,0 +1,34 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './admin.service'; +export * from './alarm.service'; +export * from './asset.service'; +export * from './attribute.service'; +export * from './audit-log.service'; +export * from './component-descriptor.service'; +export * from './customer.service'; +export * from './dashboard.service'; +export * from './device.service'; +export * from './entity.service'; +export * from './entity-relation.service'; +export * from './entity-view.service'; +export * from './event.service'; +export * from './http-utils'; +export * from './rule-chain.service'; +export * from './tenant.service'; +export * from './user.service'; +export * from './widget.service'; diff --git a/ui-ngx/src/app/core/http/rule-chain.service.ts b/ui-ngx/src/app/core/http/rule-chain.service.ts index 8619c0e3f6..4fe6b37683 100644 --- a/ui-ngx/src/app/core/http/rule-chain.service.ts +++ b/ui-ngx/src/app/core/http/rule-chain.service.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Injectable } from '@angular/core'; +import { ComponentFactory, Injectable } from '@angular/core'; import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; import { forkJoin, Observable, of } from 'rxjs/index'; import { HttpClient } from '@angular/common/http'; @@ -28,12 +28,16 @@ import { ruleNodeTypeComponentTypes, unknownNodeComponent } from '@shared/models/rule-chain.models'; import { ComponentDescriptorService } from './component-descriptor.service'; -import { LinkLabel, RuleNodeComponentDescriptor } from '@app/shared/models/rule-node.models'; +import { + IRuleNodeConfigurationComponent, + LinkLabel, + RuleNodeComponentDescriptor +} from '@app/shared/models/rule-node.models'; import { ResourcesService } from '../services/resources.service'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { EntityType } from '@shared/models/entity-type.models'; -import { deepClone } from '@core/utils'; +import { deepClone, snakeCase } from '@core/utils'; @Injectable({ providedIn: 'root' @@ -41,6 +45,7 @@ import { deepClone } from '@core/utils'; export class RuleChainService { private ruleNodeComponents: Array; + private ruleNodeConfigFactories: {[directive: string]: ComponentFactory} = {}; constructor( private http: HttpClient, @@ -105,13 +110,14 @@ export class RuleChainService { ); } - public getRuleNodeComponents(config?: RequestConfig): Observable> { + public getRuleNodeComponents(ruleNodeConfigResourcesModulesMap: {[key: string]: any}, config?: RequestConfig): + Observable> { if (this.ruleNodeComponents) { return of(this.ruleNodeComponents); } else { return this.loadRuleNodeComponents(config).pipe( mergeMap((components) => { - return this.resolveRuleNodeComponentsUiResources(components).pipe( + return this.resolveRuleNodeComponentsUiResources(components, ruleNodeConfigResourcesModulesMap).pipe( map((ruleNodeComponents) => { this.ruleNodeComponents = ruleNodeComponents; this.ruleNodeComponents.push(ruleChainNodeComponent); @@ -132,6 +138,10 @@ export class RuleChainService { } } + public getRuleNodeConfigFactory(directive: string): ComponentFactory { + return this.ruleNodeConfigFactories[directive]; + } + public getRuleNodeComponentByClazz(clazz: string): RuleNodeComponentDescriptor { const found = this.ruleNodeComponents.filter((component) => component.clazz === clazz); if (found && found.length) { @@ -192,11 +202,12 @@ export class RuleChainService { ); } - private resolveRuleNodeComponentsUiResources(components: Array): + private resolveRuleNodeComponentsUiResources(components: Array, + ruleNodeConfigResourcesModulesMap: {[key: string]: any}): Observable> { const tasks: Observable[] = []; components.forEach((component) => { - tasks.push(this.resolveRuleNodeComponentUiResources(component)); + tasks.push(this.resolveRuleNodeComponentUiResources(component, ruleNodeConfigResourcesModulesMap)); }); return forkJoin(tasks).pipe( catchError((err) => { @@ -205,13 +216,39 @@ export class RuleChainService { ); } - private resolveRuleNodeComponentUiResources(component: RuleNodeComponentDescriptor): Observable { - const uiResources = component.configurationDescriptor.nodeDefinition.uiResources; + private resolveRuleNodeComponentUiResources(component: RuleNodeComponentDescriptor, + ruleNodeConfigResourcesModulesMap: {[key: string]: any}): + Observable { + const nodeDefinition = component.configurationDescriptor.nodeDefinition; + const uiResources = nodeDefinition.uiResources; if (uiResources && uiResources.length) { + const commonResources = uiResources.filter((resource) => !resource.endsWith('.js')); + const moduleResource = uiResources.find((resource) => resource.endsWith('.js')); const tasks: Observable[] = []; - uiResources.forEach((uiResource) => { - tasks.push(this.resourcesService.loadResource(uiResource)); - }); + if (commonResources && commonResources.length) { + commonResources.forEach((resource) => { + tasks.push(this.resourcesService.loadResource(resource)); + }); + } + if (moduleResource) { + tasks.push(this.resourcesService.loadModule(moduleResource, ruleNodeConfigResourcesModulesMap).pipe( + map((res) => { + if (nodeDefinition.configDirective && nodeDefinition.configDirective.length) { + const selector = snakeCase(nodeDefinition.configDirective, '-'); + const componentFactory = res.componentFactories.find((factory) => + factory.selector === selector); + if (componentFactory) { + this.ruleNodeConfigFactories[nodeDefinition.configDirective] = componentFactory; + } else { + component.configurationDescriptor.nodeDefinition.uiResourceLoadError = + this.translate.instant('rulenode.directive-is-not-loaded', + {directiveName: nodeDefinition.configDirective}); + } + } + return of(component); + }) + )); + } return forkJoin(tasks).pipe( map((res) => { return component; @@ -231,7 +268,7 @@ export class RuleChainService { map(ruleChain => ruleChain), catchError((err) => { const ruleChain = { - id: { + id: { entityType: EntityType.RULE_CHAIN, id: ruleChainId } diff --git a/ui-ngx/src/app/core/local-storage/local-storage.service.ts b/ui-ngx/src/app/core/local-storage/local-storage.service.ts index 0c0bff21fc..10214e28a4 100644 --- a/ui-ngx/src/app/core/local-storage/local-storage.service.ts +++ b/ui-ngx/src/app/core/local-storage/local-storage.service.ts @@ -18,6 +18,7 @@ import { Injectable } from '@angular/core'; const APP_PREFIX = 'TB-'; +// @dynamic @Injectable( { providedIn: 'root' diff --git a/ui-ngx/src/app/core/public-api.ts b/ui-ngx/src/app/core/public-api.ts new file mode 100644 index 0000000000..9490c61ec1 --- /dev/null +++ b/ui-ngx/src/app/core/public-api.ts @@ -0,0 +1,23 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './api/public-api'; +export * from './http/public-api'; +export * from './local-storage/local-storage.service'; +export * from './services/public-api'; +export * from './ws/telemetry-websocket.service'; +export * from './core.state'; +export * from './core.module'; diff --git a/ui-ngx/src/app/core/services/dialog/confirm-dialog.component.ts b/ui-ngx/src/app/core/services/dialog/confirm-dialog.component.ts index 13c384624a..e5665ed2d1 100644 --- a/ui-ngx/src/app/core/services/dialog/confirm-dialog.component.ts +++ b/ui-ngx/src/app/core/services/dialog/confirm-dialog.component.ts @@ -24,6 +24,7 @@ export interface ConfirmDialogData { ok: string; } +// @dynamic @Component({ selector: 'tb-confirm-dialog', templateUrl: './confirm-dialog.component.html', diff --git a/ui-ngx/src/app/core/services/public-api.ts b/ui-ngx/src/app/core/services/public-api.ts new file mode 100644 index 0000000000..c68fc65813 --- /dev/null +++ b/ui-ngx/src/app/core/services/public-api.ts @@ -0,0 +1,32 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './script/node-script-test.service'; +export * from './broadcast.models'; +export * from './broadcast.service'; +export * from './dashboard-utils.service'; +export * from './dialog.service'; +export * from './dynamic-component-factory.service'; +export * from './item-buffer.service'; +export * from './menu.models'; +export * from './menu.service'; +export * from './notification.service'; +export * from './raf.service'; +export * from './resources.service'; +export * from './time.service'; +export * from './title.service'; +export * from './utils.service'; +export * from './window.service'; diff --git a/ui-ngx/src/app/core/services/raf.service.ts b/ui-ngx/src/app/core/services/raf.service.ts index b844dd810a..fbe6639935 100644 --- a/ui-ngx/src/app/core/services/raf.service.ts +++ b/ui-ngx/src/app/core/services/raf.service.ts @@ -20,6 +20,7 @@ import { WINDOW } from '@core/services/window.service'; export type CancelAnimationFrame = () => void; +// @dynamic @Injectable({ providedIn: 'root' }) diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts index 8b1b94d227..757f9f3b96 100644 --- a/ui-ngx/src/app/core/services/resources.service.ts +++ b/ui-ngx/src/app/core/services/resources.service.ts @@ -14,20 +14,25 @@ /// limitations under the License. /// -import { Injectable, Inject } from '@angular/core'; +import { Injectable, Inject, ModuleWithComponentFactories, Compiler, Injector } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { ReplaySubject, Observable, throwError } from 'rxjs'; +declare const SystemJS; + @Injectable({ providedIn: 'root' }) export class ResourcesService { private loadedResources: { [url: string]: ReplaySubject } = {}; + private loadedModules: { [url: string]: ReplaySubject> } = {}; private anchor = this.document.getElementsByTagName('head')[0] || this.document.getElementsByTagName('body')[0]; - constructor(@Inject(DOCUMENT) private readonly document: any) {} + constructor(@Inject(DOCUMENT) private readonly document: any, + private compiler: Compiler, + private injector: Injector) {} public loadResource(url: string): Observable { if (this.loadedResources[url]) { @@ -47,6 +52,49 @@ export class ResourcesService { return this.loadResourceByType(fileType, url); } + public loadModule(url: string, modulesMap: {[key: string]: any}): Observable> { + if (this.loadedModules[url]) { + return this.loadedModules[url].asObservable(); + } + const subject = new ReplaySubject>(); + this.loadedModules[url] = subject; + if (modulesMap) { + for (const moduleId of Object.keys(modulesMap)) { + SystemJS.set(moduleId, modulesMap[moduleId]); + } + } + SystemJS.import(url).then( + (module) => { + if (module.default) { + this.compiler.compileModuleAndAllComponentsAsync(module.default).then( + (compiled) => { + try { + compiled.ngModuleFactory.create(this.injector); + this.loadedModules[url].next(compiled); + this.loadedModules[url].complete(); + } catch (e) { + this.loadedModules[url].error(new Error(`Unable to init module from url: ${url}`)); + delete this.loadedModules[url]; + } + }, + (e) => { + this.loadedModules[url].error(new Error(`Unable to compile module from url: ${url}`)); + delete this.loadedModules[url]; + } + ); + } else { + this.loadedModules[url].error(new Error(`Module '${url}' doesn't have default export!`)); + delete this.loadedModules[url]; + } + }, + (e) => { + this.loadedModules[url].error(new Error(`Unable to load module from url: ${url}`)); + delete this.loadedModules[url]; + } + ); + return subject.asObservable(); + } + private loadResourceByType(type: 'css' | 'js', url: string): Observable { const subject = new ReplaySubject(); this.loadedResources[url] = subject; diff --git a/ui-ngx/src/app/core/services/script/node-script-test.service.ts b/ui-ngx/src/app/core/services/script/node-script-test.service.ts new file mode 100644 index 0000000000..5391c2d602 --- /dev/null +++ b/ui-ngx/src/app/core/services/script/node-script-test.service.ts @@ -0,0 +1,31 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class NodeScriptTestService { + + testNodeScript(script: string, scriptType: any, functionTitle: string, + functionName: string, argNames: string[], ruleNodeId: string): Observable { + console.log(`testNodeScript TODO: ${script}`); + return of(script); + } + +} diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index bdb3999c8f..e5c6196412 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -14,6 +14,9 @@ /// limitations under the License. /// +// tslint:disable-next-line:no-reference +/// + import { Inject, Injectable, NgZone } from '@angular/core'; import { WINDOW } from '@core/services/window.service'; import { ExceptionData } from '@app/shared/models/error.models'; @@ -67,6 +70,7 @@ const commonMaterialIcons: Array = [ 'more_horiz', 'more_vert', 'open_in 'settings', 'notifications', 'notifications_active', 'info', 'info_outline', 'warning', 'list', 'file_download', 'import_export', 'share', 'add', 'edit', 'done' ]; +// @dynamic @Injectable({ providedIn: 'root' }) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index a84ef56958..21618ba623 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -387,3 +387,12 @@ export function guid(): string { return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } + +const SNAKE_CASE_REGEXP = /[A-Z]/g; + +export function snakeCase(name: string, separator: string): string { + separator = separator || '_'; + return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => { + return (pos ? separator : '') + letter.toLowerCase(); + }); +} diff --git a/ui-ngx/src/app/core/ws/telemetry-websocket.service.ts b/ui-ngx/src/app/core/ws/telemetry-websocket.service.ts index 89b50cf0a0..331efb9150 100644 --- a/ui-ngx/src/app/core/ws/telemetry-websocket.service.ts +++ b/ui-ngx/src/app/core/ws/telemetry-websocket.service.ts @@ -40,6 +40,7 @@ const RECONNECT_INTERVAL = 2000; const WS_IDLE_TIMEOUT = 90000; const MAX_PUBLISH_COMMANDS = 10; +// @dynamic @Injectable({ providedIn: 'root' }) diff --git a/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts b/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts index cc9b6b91ea..1b4164be34 100644 --- a/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/aliases-entity-select.component.ts @@ -30,6 +30,7 @@ import { AliasesEntitySelectPanelData } from './aliases-entity-select-panel.component'; +// @dynamic @Component({ selector: 'tb-aliases-entity-select', templateUrl: './aliases-entity-select.component.html', diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts index 75b24cdf7d..dd869f16b7 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/entity-alias-dialog.component.ts @@ -73,7 +73,7 @@ export class EntityAliasDialogComponent extends DialogComponent, private fb: FormBuilder, private utils: UtilsService, - private translate: TranslateService, + public translate: TranslateService, private entityService: EntityService) { super(store, router, dialogRef); this.isAdd = data.isAdd; diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.ts b/ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.ts index d7759fac21..ebb3cb301d 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/entity-alias-select.component.ts @@ -92,7 +92,7 @@ export class EntityAliasSelectComponent implements ControlValueAccessor, OnInit, filteredEntityAliases: Observable>; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.html b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.html index c5f8539e48..3d930f6e46 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.html @@ -42,7 +42,7 @@
+ *ngFor="let entityAliasControl of entityAliasesFormArray().controls; let $index = index"> {{$index + 1}}.
diff --git a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts index 095435bfa3..5041c24dee 100644 --- a/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alias/entity-aliases-dialog.component.ts @@ -154,6 +154,11 @@ export class EntityAliasesDialogComponent extends DialogComponent + (ngModelChange)="onWidgetsBundleChanged()">
diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index a61a1648f4..956bab327d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -59,6 +59,7 @@ import { LegendConfigPanelData } from '@home/components/widget/legend-config-panel.component'; +// @dynamic @Component({ selector: 'tb-legend-config', templateUrl: './legend-config.component.html', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 767b7109b5..e5db3c2666 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -14,6 +14,9 @@ /// limitations under the License. /// +// tslint:disable-next-line:no-reference +/// + import { JsonSettingsSchema, DataKey, DatasourceData } from '@shared/models/widget.models'; export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; @@ -395,8 +398,8 @@ export function flotSettingsSchema(chartType: ChartType): JsonSettingsSchema { return schema; } -export function flotPieSettingsSchema(): JsonSettingsSchema { - return { +export const flotPieSettingsSchema: JsonSettingsSchema = + { schema: { type: 'object', title: 'Settings', @@ -477,8 +480,7 @@ export function flotPieSettingsSchema(): JsonSettingsSchema { }, 'fontSize' ] - }; -} +}; export function flotDatakeySettingsSchema(defaultShowLines: boolean): JsonSettingsSchema { return { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 8f8096f04e..b4b50e0b1c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -36,12 +36,17 @@ import { TbFlotTicksFormatterFunction, TooltipValueFormatFunction } from './flot-widget.models'; -import * as moment from 'moment'; -import * as tinycolor from 'tinycolor2'; +import * as moment_ from 'moment'; +import * as tinycolor_ from 'tinycolor2'; import { AggregationType } from '@shared/models/time/time.models'; import { CancelAnimationFrame } from '@core/services/raf.service'; import Timeout = NodeJS.Timeout; +const tinycolor = tinycolor_; +const moment = moment_; + +const flotPieSettingsSchemaValue = flotPieSettingsSchema; + export class TbFlot { private settings: TbFlotSettings; @@ -89,11 +94,11 @@ export class TbFlot { private pieAnimationLastTime: number; private pieAnimationCaf: CancelAnimationFrame; - static get pieSettingsSchema(): JsonSettingsSchema { - return flotPieSettingsSchema(); + static pieSettingsSchema(): JsonSettingsSchema { + return flotPieSettingsSchemaValue; } - static get pieDatakeySettingsSchema(): JsonSettingsSchema { + static pieDatakeySettingsSchema(): JsonSettingsSchema { return {}; } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts index 10981de3a4..75317f1108 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts @@ -38,14 +38,17 @@ import { SharedModule } from '@shared/shared.module'; import { WidgetComponentsModule } from '@home/components/widget/widget-components.module'; import { WINDOW } from '@core/services/window.service'; -import * as tinycolor from 'tinycolor2'; +import * as tinycolor_ from 'tinycolor2'; import { TbFlot } from './lib/flot-widget'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { WidgetTypeId } from '@app/shared/models/id/widget-type-id'; import { TenantId } from '@app/shared/models/id/tenant-id'; +const tinycolor = tinycolor_; + // declare var jQuery: any; +// @dynamic @Injectable() export class WidgetComponentService { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 2fcdb0a9af..df4fe6be07 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -71,7 +71,7 @@ class="tb-hint">{{ 'widget-config.maximum-datasources' | translate:{count: modelValue?.typeParameters.maxDatasources} }}
-
+
datasource.add-datasource-prompt
@@ -89,7 +89,7 @@
+ *ngFor="let datasourceControl of datasourcesFormArray().controls; let $index = index;"> {{$index + 1}}.
- diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index b5981e5700..2f34e67c9f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -128,7 +128,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont selectedTab: number; - private modelValue: WidgetConfigComponentData; + modelValue: WidgetConfigComponentData; private propagateChange = null; @@ -307,6 +307,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont this.fb.control(null, [])); } + datasourcesFormArray(): FormArray { + return this.dataSettings.get('datasources') as FormArray; + } + registerOnChange(fn: any): void { this.propagateChange = fn; } diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.ts index fe0f2655c2..0b41ca71d0 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-page.component.ts @@ -86,6 +86,7 @@ import { import { ImportExportService } from '@home/components/import-export/import-export.service'; import { AuthState } from '@app/core/auth/auth.models'; +// @dynamic @Component({ selector: 'tb-dashboard-page', templateUrl: './dashboard-page.component.html', diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts index 0d1e1c6db1..cb5825f677 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-routing.module.ts @@ -90,6 +90,7 @@ const routes: Routes = [ } ]; +// @dynamic @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/states/entity-state-controller.component.ts b/ui-ngx/src/app/modules/home/pages/dashboard/states/entity-state-controller.component.ts index 316a1a139e..c9d50a3270 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/states/entity-state-controller.component.ts +++ b/ui-ngx/src/app/modules/home/pages/dashboard/states/entity-state-controller.component.ts @@ -47,7 +47,7 @@ import { map } from 'rxjs/operators'; }) export class EntityStateControllerComponent extends StateControllerComponent implements OnInit, OnDestroy { - private selectedStateIndex = -1; + selectedStateIndex = -1; constructor(protected router: Router, protected route: ActivatedRoute, diff --git a/ui-ngx/src/app/modules/home/pages/public-api.ts b/ui-ngx/src/app/modules/home/pages/public-api.ts new file mode 100644 index 0000000000..8100286509 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/public-api.ts @@ -0,0 +1,17 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './home-pages.module'; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html new file mode 100644 index 0000000000..cb6f73385a --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html @@ -0,0 +1,56 @@ + +
+ +

rulenode.add

+ +
+ +
+ + +
+
+ + +
+
+
+ + + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.html index 5dd617479c..593613f143 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.component.html @@ -45,7 +45,7 @@ - +
rulenode.no-link-labels-found diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.conponent.ts b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.conponent.ts index c7303f145f..ca165caa4d 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.conponent.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/link-labels.conponent.ts @@ -94,9 +94,9 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan filteredLabels: Observable>; - private labels: Array = []; + labels: Array = []; - private searchText = ''; + searchText = ''; private propagateChange = (v: any) => { }; @@ -190,7 +190,7 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan } add(event: MatChipInputEvent): void { - if (!this.matAutocomplete.isOpen) { + if (!this.matAutocomplete.isOpen || this.allowCustom) { this.transformLinkLabel(event.value); } } @@ -250,8 +250,8 @@ export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChan if (this.required) { this.chipList.errorState = false; } + this.updateModel(); } - this.updateModel(); } clear(value: string = '') { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html new file mode 100644 index 0000000000..5ce6a69cc7 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html @@ -0,0 +1,28 @@ + +
+ +
{{definedDirectiveError}}
+ + +
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.scss new file mode 100644 index 0000000000..774758fdbd --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.scss @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host { + tb-json-object-edit.tb-rule-node-configuration-json { + display: block; + height: 300px; + } + + .tb-rulenode-directive-error { + font-size: 13px; + font-weight: 400; + color: rgb(221, 44, 0); + } +} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts new file mode 100644 index 0000000000..11ebc02284 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts @@ -0,0 +1,208 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + AfterViewInit, + Component, ElementRef, + EventEmitter, forwardRef, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewChild, + Compiler, + Injector, ComponentRef, OnDestroy +} from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgForm, Validators } from '@angular/forms'; +import { FcRuleNode, FcRuleEdge } from './rulechain-page.models'; +import { RuleNodeType, LinkLabel, RuleNodeDefinition, RuleNodeConfiguration, IRuleNodeConfigurationComponent } from '@shared/models/rule-node.models'; +import { EntityType } from '@shared/models/entity-type.models'; +import { Observable, of, Subscription } from 'rxjs'; +import { RuleChainService } from '@core/http/rule-chain.service'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { deepClone } from '@core/utils'; +import { EntityAlias } from '@shared/models/alias.models'; +import { TruncatePipe } from '@shared/pipe/truncate.pipe'; +import { MatChipList, MatAutocomplete, MatChipInputEvent, MatAutocompleteSelectedEvent } from '@angular/material'; +import { TranslateService } from '@ngx-translate/core'; +import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; +import { catchError, map, mergeMap, share } from 'rxjs/operators'; +import { DynamicWidgetComponent } from '@home/components/widget/dynamic-widget.component'; +import { SharedModule } from '@shared/shared.module'; +import { WidgetComponentsModule } from '@home/components/widget/widget-components.module'; +import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service'; +import { ViewContainerRef } from '@angular/core'; +import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; + +@Component({ + selector: 'tb-rule-node-config', + templateUrl: './rule-node-config.component.html', + styleUrls: ['./rule-node-config.component.scss'], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => RuleNodeConfigComponent), + multi: true + }] +}) +export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, OnDestroy, AfterViewInit { + + @ViewChild('definedConfigContent', {read: ViewContainerRef, static: true}) definedConfigContainer: ViewContainerRef; + + @ViewChild('jsonObjectEditComponent', {static: false}) jsonObjectEditComponent: JsonObjectEditComponent; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + @Input() + disabled: boolean; + + @Input() + ruleNodeId: string; + + nodeDefinitionValue: RuleNodeDefinition; + + @Input() + set nodeDefinition(nodeDefinition: RuleNodeDefinition) { + if (this.nodeDefinitionValue !== nodeDefinition) { + this.nodeDefinitionValue = nodeDefinition; + if (this.nodeDefinitionValue) { + this.validateDefinedDirective(); + } + } + } + + get nodeDefinition(): RuleNodeDefinition { + return this.nodeDefinitionValue; + } + + definedDirectiveError: string; + + ruleNodeConfigFormGroup: FormGroup; + + changeSubscription: Subscription; + + private definedConfigComponentRef: ComponentRef; + private definedConfigComponent: IRuleNodeConfigurationComponent; + + private configuration: RuleNodeConfiguration; + + private propagateChange = (v: any) => { }; + + constructor(private translate: TranslateService, + private ruleChainService: RuleChainService, + private fb: FormBuilder) { + this.ruleNodeConfigFormGroup = this.fb.group({ + configuration: [null, Validators.required] + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit(): void { + } + + ngOnDestroy(): void { + if (this.definedConfigComponentRef) { + this.definedConfigComponentRef.destroy(); + } + } + + ngAfterViewInit(): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.ruleNodeConfigFormGroup.disable({emitEvent: false}); + } else { + this.ruleNodeConfigFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: RuleNodeConfiguration): void { + this.configuration = value; + if (this.changeSubscription) { + this.changeSubscription.unsubscribe(); + this.changeSubscription = null; + } + if (this.definedConfigComponent) { + this.definedConfigComponent.configuration = this.configuration; + this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => { + this.updateModel(configuration); + }); + } else { + this.ruleNodeConfigFormGroup.get('configuration').patchValue(value, {emitEvent: false}); + this.changeSubscription = this.ruleNodeConfigFormGroup.get('configuration').valueChanges.subscribe( + (configuration: RuleNodeConfiguration) => { + this.updateModel(configuration); + } + ); + } + } + + useDefinedDirective(): boolean { + return this.nodeDefinition && + (this.nodeDefinition.configDirective && + this.nodeDefinition.configDirective.length) && !this.definedDirectiveError; + } + + private updateModel(configuration: RuleNodeConfiguration) { + if (this.definedConfigComponent || this.ruleNodeConfigFormGroup.valid) { + this.propagateChange(configuration); + } else { + this.propagateChange(this.required ? null : configuration); + } + } + + private validateDefinedDirective() { + if (this.definedConfigComponentRef) { + this.definedConfigComponentRef.destroy(); + this.definedConfigComponentRef = null; + } + if (this.nodeDefinition.uiResourceLoadError && this.nodeDefinition.uiResourceLoadError.length) { + this.definedDirectiveError = this.nodeDefinition.uiResourceLoadError; + } else if (this.nodeDefinition.configDirective && this.nodeDefinition.configDirective.length) { + if (this.changeSubscription) { + this.changeSubscription.unsubscribe(); + this.changeSubscription = null; + } + this.definedConfigContainer.clear(); + const factory = this.ruleChainService.getRuleNodeConfigFactory(this.nodeDefinition.configDirective); + this.definedConfigComponentRef = this.definedConfigContainer.createComponent(factory); + this.definedConfigComponent = this.definedConfigComponentRef.instance; + this.definedConfigComponent.ruleNodeId = this.ruleNodeId; + this.definedConfigComponent.configuration = this.configuration; + this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => { + this.updateModel(configuration); + }); + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index 1d27fcf7f5..6a5f070c8b 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -31,7 +31,11 @@ {{ 'rulenode.debug-mode' | translate }}
- TODO: tb-rule-node-config + +
rulenode.description diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index 8a3f654824..74b203ccd5 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -70,6 +70,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O this.ruleNodeFormGroup = this.fb.group({ name: [this.ruleNode.name, [Validators.required]], debugMode: [this.ruleNode.debugMode, []], + configuration: [this.ruleNode.configuration, [Validators.required]], additionalInfo: this.fb.group( { description: [this.ruleNode.additionalInfo ? this.ruleNode.additionalInfo.description : ''], diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 04e86b6090..a7f4a6e92c 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -151,7 +151,6 @@ export class RuleChainPageComponent extends PageComponent return source.type === FlowchartConstants.rightConnectorType && destination.type === FlowchartConstants.leftConnectorType; }, createEdge: (event, edge: FcRuleEdge) => { - console.log('TODO'); const sourceNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.source) as FcRuleNode; if (sourceNode.component.type === RuleNodeType.INPUT) { const destNode = this.ruleChainCanvas.modelService.nodes.getNodeByConnectorId(edge.destination) as FcRuleNode; @@ -185,9 +184,8 @@ export class RuleChainPageComponent extends PageComponent } } }, - dropNode: (event, node) => { - console.log('TODO dropNode'); - console.log(node); + dropNode: (event, node: FcRuleNode) => { + this.addRuleNode(node); } }; @@ -269,7 +267,7 @@ export class RuleChainPageComponent extends PageComponent this.createRuleChainModel(); } - private updateRuleChainLibrary() { + updateRuleChainLibrary() { const search = this.ruleNodeTypeSearch.toUpperCase(); const res = this.ruleNodeComponents.filter( (ruleNodeComponent) => ruleNodeComponent.name.toUpperCase().includes(search)); @@ -734,6 +732,46 @@ export class RuleChainPageComponent extends PageComponent this.createRuleChainModel(); } + addRuleNode(ruleNode: FcRuleNode) { + ruleNode.configuration = deepClone(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration); + const ruleChainId = this.ruleChain.id ? this.ruleChain.id.id : null; + this.dialog.open(AddRuleNodeDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + ruleNode, + ruleChainId + } + }).afterClosed().subscribe( + (addedRuleNode) => { + if (addedRuleNode) { + addedRuleNode.id = 'rule-chain-node-' + this.nextNodeID++; + addedRuleNode.connectors = []; + if (addedRuleNode.component.configurationDescriptor.nodeDefinition.inEnabled) { + addedRuleNode.connectors.push( + { + id: (this.nextConnectorID++) + '', + type: FlowchartConstants.leftConnectorType + } + ); + } + if (addedRuleNode.component.configurationDescriptor.nodeDefinition.outEnabled) { + addedRuleNode.connectors.push( + { + id: (this.nextConnectorID++) + '', + type: FlowchartConstants.rightConnectorType + } + ); + } + this.ruleChainModel.nodes.push(addedRuleNode); + this.onModelChanged(); + this.updateRuleNodesHighlight(); + } + } + ); + } + addRuleNodeLink(link: FcRuleEdge, labels: {[label: string]: LinkLabel}, allowCustomLabels: boolean): Observable { return this.dialog.open(AddRuleNodeLinkDialogComponent, { @@ -885,3 +923,56 @@ export class AddRuleNodeLinkDialogComponent extends DialogComponent + implements OnInit, ErrorStateMatcher { + + ruleNode: FcRuleNode; + ruleChainId: string; + + submitted = false; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: AddRuleNodeDialogData, + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, + public dialogRef: MatDialogRef) { + super(store, router, dialogRef); + + this.ruleNode = this.data.ruleNode; + this.ruleChainId = this.data.ruleChainId; + } + + ngOnInit(): void { + } + + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); + const customErrorState = !!(control && control.invalid && this.submitted); + return originalErrorState || customErrorState; + } + + helpLinkIdForRuleNodeType(): string { + return getRuleNodeHelpLink(this.ruleNode.component); + } + + cancel(): void { + this.dialogRef.close(null); + } + + add(): void { + this.submitted = true; + this.dialogRef.close(this.ruleNode); + } +} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts index 93f25ecc7f..f080ad64c8 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-routing.module.ts @@ -39,6 +39,29 @@ import { RuleChainPageComponent } from '@home/pages/rulechain/rulechain-page.com import { RuleNodeComponentDescriptor } from '@shared/models/rule-node.models'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; +import * as AngularCommon from '@angular/common'; +import * as AngularCore from '@angular/core'; +import * as AngularForms from '@angular/forms'; +import * as AngularCdkCoercion from '@angular/cdk/coercion'; +import * as NgrxStore from '@ngrx/store'; +import * as TranslateCore from '@ngx-translate/core'; +import * as TbCore from '@core/public-api'; +import * as TbShared from '@shared/public-api'; + +declare const SystemJS; + +const ruleNodeConfigResourcesModulesMap = { + '@angular/core': SystemJS.newModule(AngularCore), + '@angular/common': SystemJS.newModule(AngularCommon), + '@angular/forms': SystemJS.newModule(AngularForms), + '@ngrx/store': SystemJS.newModule(NgrxStore), + '@ngx-translate/core': SystemJS.newModule(TranslateCore), + '@core/public-api': SystemJS.newModule(TbCore), + '@shared/public-api': SystemJS.newModule(TbShared) +}; + +const t = SystemJS.newModule(AngularCore); + @Injectable() export class RuleChainResolver implements Resolve { @@ -71,7 +94,7 @@ export class RuleNodeComponentsResolver implements Resolve> { - return this.ruleChainService.getRuleNodeComponents(); + return this.ruleChainService.getRuleNodeComponents(ruleNodeConfigResourcesModulesMap); } } @@ -150,6 +173,7 @@ const routes: Routes = [ } ]; +// @dynamic @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts index 665d287320..8705cfaeff 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain.module.ts @@ -21,19 +21,21 @@ import {RuleChainComponent} from '@modules/home/pages/rulechain/rulechain.compon import {RuleChainRoutingModule} from '@modules/home/pages/rulechain/rulechain-routing.module'; import {HomeComponentsModule} from '@modules/home/components/home-components.module'; import { RuleChainTabsComponent } from '@home/pages/rulechain/rulechain-tabs.component'; -import { RuleChainPageComponent, AddRuleNodeLinkDialogComponent } from './rulechain-page.component'; +import { RuleChainPageComponent, AddRuleNodeLinkDialogComponent, AddRuleNodeDialogComponent } from './rulechain-page.component'; import { RuleNodeComponent } from '@home/pages/rulechain/rulenode.component'; import { FC_NODE_COMPONENT_CONFIG } from 'ngx-flowchart/dist/ngx-flowchart'; import { RuleNodeDetailsComponent } from './rule-node-details.component'; import { RuleNodeLinkComponent } from './rule-node-link.component'; import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.conponent'; +import { RuleNodeConfigComponent } from './rule-node-config.component'; @NgModule({ entryComponents: [ RuleChainComponent, RuleChainTabsComponent, RuleNodeComponent, - AddRuleNodeLinkDialogComponent + AddRuleNodeLinkDialogComponent, + AddRuleNodeDialogComponent ], declarations: [ RuleChainComponent, @@ -41,9 +43,11 @@ import { LinkLabelsComponent } from '@home/pages/rulechain/link-labels.conponent RuleChainPageComponent, RuleNodeComponent, RuleNodeDetailsComponent, + RuleNodeConfigComponent, LinkLabelsComponent, RuleNodeLinkComponent, - AddRuleNodeLinkDialogComponent + AddRuleNodeLinkDialogComponent, + AddRuleNodeDialogComponent ], providers: [ { diff --git a/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.html b/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.html index 092aa03842..a6444c325c 100644 --- a/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.html @@ -34,8 +34,8 @@ user.activation-method - - {{ activationMethodTranslations.get(activationMethods[activationMethod]) | translate }} + + {{ activationMethodTranslations.get(activationMethod) | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts index 95e9d678da..b6edc66ee6 100644 --- a/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/user/add-user-dialog.component.ts @@ -49,7 +49,7 @@ export class AddUserDialogComponent extends DialogComponent>; - private searchText = ''; + searchText = ''; private propagateChange = (v: any) => { }; diff --git a/ui-ngx/src/app/shared/components/dashboard-select.component.ts b/ui-ngx/src/app/shared/components/dashboard-select.component.ts index c78ef98cc2..73652174e7 100644 --- a/ui-ngx/src/app/shared/components/dashboard-select.component.ts +++ b/ui-ngx/src/app/shared/components/dashboard-select.component.ts @@ -40,6 +40,7 @@ import { } from './dashboard-select-panel.component'; import { NULL_UUID } from '@shared/models/id/has-uuid'; +// @dynamic @Component({ selector: 'tb-dashboard-select', templateUrl: './dashboard-select.component.html', diff --git a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts index 815c3ba8da..aedae5285d 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts @@ -94,7 +94,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit filteredEntities: Observable>>; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/entity/entity-keys-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-keys-list.component.ts index dc006ecf57..de5e0ffcda 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-keys-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-keys-list.component.ts @@ -92,7 +92,7 @@ export class EntityKeysListComponent implements ControlValueAccessor, OnInit, Af separatorKeysCodes: number[] = [ENTER, COMMA, SEMICOLON]; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/entity/entity-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-list.component.ts index 54cb2f37db..af40b416b8 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-list.component.ts @@ -90,7 +90,7 @@ export class EntityListComponent implements ControlValueAccessor, OnInit, AfterV entities: Array> = []; filteredEntities: Observable>>; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts index 7e809471bf..111fb0082e 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-autocomplete.component.ts @@ -79,7 +79,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, private broadcastSubscription: Subscription; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts index 58ed2600b5..20a9658c7f 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts @@ -106,7 +106,7 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, separatorKeysCodes: number[] = [ENTER, COMMA, SEMICOLON]; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts index 8360699f60..97cec76f72 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts @@ -102,7 +102,7 @@ export class EntityTypeListComponent implements ControlValueAccessor, OnInit, Af placeholder: string; secondaryPlaceholder: string; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/fab-toolbar.component.ts b/ui-ngx/src/app/shared/components/fab-toolbar.component.ts index 92447f36b4..144a3910aa 100644 --- a/ui-ngx/src/app/shared/components/fab-toolbar.component.ts +++ b/ui-ngx/src/app/shared/components/fab-toolbar.component.ts @@ -63,6 +63,7 @@ export class FabActionsDirective implements OnInit { } +// @dynamic @Component({ selector: 'mat-fab-toolbar', templateUrl: './fab-toolbar.component.html', diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts index 8100ea3a3c..e3b0dcd7e1 100644 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts +++ b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts @@ -35,7 +35,7 @@ import { deepClone, isString } from '@app/core/utils'; import { TranslateService } from '@ngx-translate/core'; import { JsonFormProps } from './react/json-form.models'; import inspector from 'schema-inspector'; -import * as tinycolor from 'tinycolor2'; +import * as tinycolor_ from 'tinycolor2'; import { DialogService } from '@app/core/services/dialog.service'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; @@ -43,6 +43,8 @@ import ReactSchemaForm from './react/json-form-react'; import JsonFormUtils from './react/json-form-utils'; import { JsonFormComponentData } from './json-form-component.models'; +const tinycolor = tinycolor_; + @Component({ selector: 'tb-json-form', templateUrl: './json-form.component.html', diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx index 9bb42df9db..1cc48877b8 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-ace-editor.tsx @@ -20,7 +20,6 @@ import reactCSS from 'reactcss'; import ReactAce from 'react-ace'; import Button from '@material-ui/core/Button'; import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; -import * as tinycolor from 'tinycolor2'; import { IEditorProps } from 'react-ace/src/types'; interface ThingsboardAceEditorProps extends JsonFormFieldProps { diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx index 74025e2b32..aa4336dad8 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-color.tsx @@ -17,13 +17,15 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import ThingsboardBaseComponent from './json-form-base-component'; import reactCSS from 'reactcss'; -import * as tinycolor from 'tinycolor2'; +import * as tinycolor_ from 'tinycolor2'; import TextField from '@material-ui/core/TextField'; import { JsonFormFieldProps, JsonFormFieldState } from '@shared/components/json-form/react/json-form.models'; import IconButton from '@material-ui/core/IconButton'; import ClearIcon from '@material-ui/icons/Clear'; import Tooltip from '@material-ui/core/Tooltip'; +const tinycolor = tinycolor_; + interface ThingsboardColorState extends JsonFormFieldState { color: tinycolor.ColorFormats.RGBA | null; focused: boolean; diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx index 145c2aedb9..45e9513ef9 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form-schema-form.tsx @@ -35,7 +35,8 @@ import ThingsboardFieldSet from './json-form-fieldset'; import { JsonFormProps, GroupInfo, JsonFormData, onChangeFn, OnColorClickFn } from './json-form.models'; import _ from 'lodash'; -import * as tinycolor from 'tinycolor2'; +import * as tinycolor_ from 'tinycolor2'; +const tinycolor = tinycolor_; class ThingsboardSchemaForm extends React.Component { diff --git a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts index f53d52177e..7e3c466e24 100644 --- a/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts +++ b/ui-ngx/src/app/shared/components/json-form/react/json-form.models.ts @@ -18,7 +18,9 @@ import { isUndefined, isDefined, isString } from '@app/core/utils'; import * as equal from 'deep-equal'; import ObjectPath from 'objectpath'; import * as React from 'react'; -import * as tinycolor from 'tinycolor2'; +import * as tinycolor_ from 'tinycolor2'; + +const tinycolor = tinycolor_; export interface SchemaValidationResult { valid: boolean; diff --git a/ui-ngx/src/app/shared/components/mat-chip-draggable.directive.ts b/ui-ngx/src/app/shared/components/mat-chip-draggable.directive.ts index 8fa1cd86d5..3d20f45a39 100644 --- a/ui-ngx/src/app/shared/components/mat-chip-draggable.directive.ts +++ b/ui-ngx/src/app/shared/components/mat-chip-draggable.directive.ts @@ -49,7 +49,7 @@ export class MatChipDraggableDirective implements AfterViewInit { private elementRef: ElementRef) { } - @HostListener('document:mouseup', ['$event']) + @HostListener('document:mouseup') onDocumentMouseUp() { this.draggableChips.forEach((draggableChip) => { draggableChip.preventDrag = false; diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts new file mode 100644 index 0000000000..01943cf9f2 --- /dev/null +++ b/ui-ngx/src/app/shared/components/public-api.ts @@ -0,0 +1,17 @@ +/// +/// Copyright © 2016-2019 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +export * from './page.component'; diff --git a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts index 3c1536b361..489c87d7df 100644 --- a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.ts @@ -69,7 +69,7 @@ export class RelationTypeAutocompleteComponent implements ControlValueAccessor, filteredRelationTypes: Observable>; - private searchText = ''; + searchText = ''; private dirty = false; diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.html b/ui-ngx/src/app/shared/components/time/timewindow.component.html index d8e94e6227..e503382dc5 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.html @@ -17,7 +17,7 @@ --> @@ -25,20 +25,20 @@ class="tb-timewindow" fxLayout="row" fxLayoutAlign="start center"> {{innerValue?.displayValue}}