Commit 42c52bfdba14d846720fee003e33f57982469954

Authored by ArtemHalushko
Committed by GitHub
1 parent 1af55e84

Map/3.0 (#2535)

* add base map infrastructure

* add leaflet css

* add tencent map

* add google maps support

* added image map support

* refactor schemes

* here maps support && WIP on markers

* add simple marker suppor

* data update & polyline support

* map bouds support

* add some settings support

* add map provider select to settings

* labels support

* WIP on trip animation widget

* WIP on history control and route interpolation

* trip-animation map provider & custom markers

* comleted track marker & history controls

* add license headers

* label fix & tooltips support

* WIP on polygons

* marker dropping support

* add polygon support

* add label to trip animation

* WIP on tooltips

* lint anf typed leaflet AddMarker

* some typing and poly improvements

* add typing

* add marker creation

* update proxy

* save position fix

Co-authored-by: Artem Halushko <ahalushko@thingboards.io>
Co-authored-by: Adsumus <artemtv42@gmail.com>
Showing 44 changed files with 3926 additions and 54 deletions
@@ -13,4 +13,4 @@ @@ -13,4 +13,4 @@
13 See the Apache Version 2.0 License for specific language governing permissions 13 See the Apache Version 2.0 License for specific language governing permissions
14 and limitations under the License. 14 and limitations under the License.
15 ***************************************************************************** */var g=function(e,t){return(g=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 y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function C(e){var t="function"==typeof Symbol&&e[Symbol.iterator],r=0;return t?t.call(e):{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}}}var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"<div></div>"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'<section [formGroup]="attributesConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>attribute.attributes-scope</mat-label>\n <mat-select formControlName="scope" required>\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'<section [formGroup]="timeseriesConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.default-ttl</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="defaultTTL" required>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'required\')">\n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'min\')">\n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'<section [formGroup]="rpcRequestConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.timeout-sec</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="timeoutInSeconds" required>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'<section [formGroup]="logConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.to-string</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-to-string-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'<section [formGroup]="assignCustomerConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-checkbox fxFlex formControlName="createCustomerIfNotExists" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="customerCacheExpiration">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'<section [formGroup]="clearAlarmConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.alarm-details-builder</label>\n <tb-js-func #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-details-function\' | translate }}\n </button>\n </div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="clearAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'<section [formGroup]="createAlarmConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.alarm-details-builder</label>\n <tb-js-func #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-details-function\' | translate }}\n </button>\n </div>\n <mat-checkbox formControlName="useMessageAlarmData" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false">\n <section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="createAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.alarm-severity</mat-label>\n <mat-select formControlName="severity" required>\n <mat-option *ngFor="let severity of alarmSeverities" [value]="severity">\n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n <mat-checkbox formControlName="propagate" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.propagate\' | translate }}\n </mat-checkbox>\n <section *ngIf="createAlarmConfigForm.get(\'propagate\').value === true">\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.relation-types-list</mat-label>\n <mat-chip-list #relationTypesChipList>\n <mat-chip\n *ngFor="let key of createAlarmConfigForm.get(\'relationTypes\').value;"\n (removed)="removeKey(key, \'relationTypes\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.relation-types-list\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="relationTypesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'relationTypes\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n <mat-hint innerHTML="{{ \'tb.rulenode.relation-types-list-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </section>\n </section>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'<section [formGroup]="createRelationConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout="row" fxLayoutGap="8px">\n <tb-entity-type-select\n showLabel\n style="min-width: 100px;"\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value" fxFlex class="mat-block" style="padding-bottom: 32px;">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="createRelationConfigForm.get(\'entityNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n fxFlex class="mat-block" style="padding-bottom: 32px;">\n <mat-label translate>tb.rulenode.entity-type-pattern</mat-label>\n <input required matInput formControlName="entityTypePattern">\n <mat-error *ngIf="createRelationConfigForm.get(\'entityTypePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.relation-type-pattern</mat-label>\n <input required matInput formControlName="relationType">\n <mat-error *ngIf="createRelationConfigForm.get(\'relationType\').hasError(\'required\')">\n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.relation-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <section *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET">\n <mat-checkbox formControlName="createEntityIfNotExists">\n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.create-entity-if-not-exists-hint</div>\n </section>\n <mat-checkbox formControlName="removeCurrentRelations">\n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.remove-current-relations-hint</div>\n <mat-checkbox formControlName="changeOriginatorToRelatedEntity">\n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.change-originator-to-related-entity-hint</div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.entity-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="entityCacheExpiration">\n <mat-error *ngIf="createRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="createRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'<section [formGroup]="msgDelayConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMetadataPeriodInSecondsPatterns">\n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.use-metadata-period-in-seconds-patterns-hint</div>\n <mat-form-field *ngIf="msgDelayConfigForm.get(\'useMetadataPeriodInSecondsPatterns\').value !== true; else periodInSecondsPattern"\n class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <ng-template #periodInSecondsPattern>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.period-in-seconds-pattern</mat-label>\n <input required matInput formControlName="periodInSecondsPattern">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSecondsPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.period-in-seconds-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </ng-template>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.max-pending-messages</mat-label>\n <input required type="number" min="1" max="100000" step="1" matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'<section [formGroup]="deleteRelationConfigForm" fxLayout="column">\n <mat-checkbox formControlName="deleteForSingleEntity">\n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.delete-relation-hint</div>\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div *ngIf="deleteRelationConfigForm.get(\'deleteForSingleEntity\').value" fxLayout="row" fxLayoutGap="8px">\n <tb-entity-type-select\n showLabel\n style="min-width: 100px;"\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="deleteRelationConfigForm.get(\'entityType\').value" fxFlex class="mat-block" style="padding-bottom: 32px;">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="deleteRelationConfigForm.get(\'entityNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.relation-type-pattern</mat-label>\n <input required matInput formControlName="relationType">\n <mat-error *ngIf="deleteRelationConfigForm.get(\'relationType\').hasError(\'required\')">\n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.relation-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.entity-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="entityCacheExpiration">\n <mat-error *ngIf="deleteRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="deleteRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'<section [formGroup]="generatorConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-count</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="msgCount">\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'required\')">\n {{ \'tb.rulenode.message-count-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'min\')">\n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div fxLayout="column">\n <label class="tb-small">{{ \'tb.rulenode.originator\' | translate }}</label>\n <tb-entity-select\n required="false"\n formControlName="originator">\n </tb-entity-select>\n </div>\n <label translate class="tb-title no-padding">tb.rulenode.generate</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-generator-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var D,O=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var j,U,G,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(j||(j={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(G||(G={}));var Q,z=new Map([[G.STANDARD,"tb.rulenode.sqs-queue-standard"],[G.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var W=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'<section [formGroup]="geoActionConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.latitude-key-name</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.longitude-key-name</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox fxFlex formControlName="fetchPerimeterInfoFromMessageMetadata" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n </mat-checkbox>\n <div fxLayout="row" *ngIf="!geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.perimeter-type</mat-label>\n <mat-select formControlName="perimeterType" required>\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column"\n *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-latitude</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-longitude</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range-units</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="column" *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field class="mat-block" hintLabel="{{\'tb.rulenode.polygon-definition-hint\' | translate}}" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minInsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration-time-unit</mat-label>\n <mat-select formControlName="minInsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minOutsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration-time-unit</mat-label>\n <mat-select formControlName="minOutsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),J=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'<section [formGroup]="msgCountConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.interval-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="interval">\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'required\')">\n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'min\')">\n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.output-timeseries-key-prefix</mat-label>\n <input required matInput formControlName="telemetryPrefix">\n <mat-error *ngIf="msgCountConfigForm.get(\'telemetryPrefix\').hasError(\'required\')">\n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Y=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'<section [formGroup]="rpcReplyConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Z=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'<section [formGroup]="saveToCustomTableConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.custom-table-name</mat-label>\n <input required matInput formControlName="tableName">\n <mat-error *ngIf="saveToCustomTableConfigForm.get(\'tableName\').hasError(\'required\')">\n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.custom-table-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.message-field"\n keyRequiredText="tb.rulenode.message-field-required"\n valText="tb.rulenode.table-col"\n valRequiredText="tb.rulenode.table-col-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),X=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'<section fxLayout="column" class="tb-kv-map-config" [formGroup]="kvListFormGroup">\n <div class="header" fxFlex fxLayout="row" fxLayoutGap="8px">\n <span class="cell" fxFlex translate>{{ keyText }}</span>\n <span class="cell" fxFlex translate>{{ valText }}</span>\n <span [fxShow]="!disabled" style="width: 52px;" innerHTML="&nbsp"></span>\n </div>\n <div class="body">\n <div class="row" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"\n formArrayName="keyVals"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">\n <mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="cell mat-block">\n <mat-label></mat-label>\n <input [formControl]="keyValControl.get(\'key\')" matInput required\n placeholder="{{ keyText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'key\').hasError(\'required\')">\n {{ keyRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="cell mat-block">\n <mat-label></mat-label>\n <input [formControl]="keyValControl.get(\'value\')" matInput required\n placeholder="{{ valText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'value\').hasError(\'required\')">\n {{ valRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <button mat-button mat-icon-button color="primary"\n [fxShow]="!disabled"\n type="button"\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n <tb-error [error]="ngControl.hasError(\'kvMapRequired\')\n ? translate.instant(requiredText) : \'\'"></tb-error>\n <div style="margin-top: 8px;">\n <button mat-button mat-raised-button color="primary"\n [fxShow]="!disabled"\n [disabled]="isLoading$ | async"\n (click)="addKeyVal()"\n type="button"\n matTooltip="{{ \'tb.key-val.add-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n </div>\n</section>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .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}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'<section fxLayout="column" [formGroup]="deviceRelationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly" style="padding-bottom: 16px;">\n {{ \'relation.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: rgba(0,0,0,0.57);" translate>relation.relation-type</div>\n <tb-relation-type-autocomplete\n fxFlex\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <div class="mat-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>device.device-types</div>\n <tb-entity-subtype-list\n required\n [entityType]="entityType.DEVICE"\n formControlName="deviceTypes">\n </tb-entity-subtype-list>\n</section>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'<section fxLayout="column" [formGroup]="relationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly" style="padding-bottom: 16px;">\n {{ \'relation.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: rgba(0,0,0,0.57);" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters"\n ></tb-relation-filters>\n</section>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),re=function(e){function r(t,r,n,o){var i,l,m=e.call(this,t)||this;m.store=t,m.translate=r,m.truncate=n,m.fb=o,m.placeholder="tb.rulenode.message-type",m.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],m.messageTypes=[],m.messageTypesList=[],m.searchText="",m.propagateChange=function(e){},m.messageTypeConfigForm=m.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;m.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return m}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'<mat-form-field [formGroup]="messageTypeConfigForm" style="width: 100%;">\n <mat-label *ngIf="label" translate>{{ label }}</mat-label>\n <mat-chip-list #chipList [required]="required">\n <mat-chip\n *ngFor="let messageType of messageTypes"\n [selectable]="true"\n [removable]="true"\n (removed)="remove(messageType)">\n {{messageType.name}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{ placeholder | translate }}"\n style="max-width: 200px;"\n #messageTypeInput\n (focusin)="onFocus()"\n formControlName="messageType"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="messageTypeAutocomplete"\n [matChipInputFor]="chipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="add($event)">\n </mat-chip-list>\n <mat-autocomplete #messageTypeAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="selected($event)"\n [displayWith]="displayMessageTypeFn">\n <mat-option *ngFor="let messageType of filteredMessageTypes | async" [value]="messageType">\n <span [innerHTML]="messageType.name | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredMessageTypes | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">\n <span translate>tb.rulenode.no-message-types-found</span>\n </div>\n <ng-template #searchNotEmpty>\n <span>\n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, &apos;...&apos;)}) | async }}\n </span>\n </ng-template>\n <span>\n <a translate (click)="createMessageType($event, searchText)">tb.rulenode.create-new-message-type</a>\n </span>\n </div>\n </mat-option>\n </mat-autocomplete>\n <mat-error *ngIf="chipList.errorState">\n {{ \'tb.rulenode.message-types-required\' | translate }}\n </mat-error>\n</mat-form-field>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),ne=function(){function e(){}return e=b([t.NgModule({declarations:[X,ee,te,re],imports:[r.CommonModule,a.SharedModule,m.HomeComponentsModule],exports:[X,ee,te,re]})],e)}(),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'<section [formGroup]="unassignCustomerConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="customerCacheExpiration">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'<section [formGroup]="snsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.topic-arn-pattern</mat-label>\n <input required matInput formControlName="topicArnPattern">\n <mat-error *ngIf="snsConfigForm.get(\'topicArnPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.topic-arn-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="snsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="snsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="snsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=G,n.sqsQueueTypes=Object.keys(G),n.sqsQueueTypeTranslationsMap=z,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'<section [formGroup]="sqsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.queue-type</mat-label>\n <mat-select formControlName="queueType" required>\n <mat-option *ngFor="let type of sqsQueueTypes" [value]="type">\n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.queue-url-pattern</mat-label>\n <input required matInput formControlName="queueUrlPattern">\n <mat-error *ngIf="sqsConfigForm.get(\'queueUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.queue-url-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="sqsConfigForm.get(\'queueType\').value === sqsQueueType.STANDARD" class="mat-block">\n <mat-label translate>tb.rulenode.delay-seconds</mat-label>\n <input required type="number" min="0" max="900" step="1" matInput formControlName="delaySeconds">\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n </mat-error>\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'max\')">\n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" translate>tb.rulenode.message-attributes-hint</div>\n <tb-kv-map-config\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="sqsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="sqsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="sqsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'<section [formGroup]="pubSubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.gcp-project-id</mat-label>\n <input required matInput formControlName="projectId">\n <mat-error *ngIf="pubSubConfigForm.get(\'projectId\').hasError(\'required\')">\n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.pubsub-topic-name</mat-label>\n <input required matInput formControlName="topicName">\n <mat-error *ngIf="pubSubConfigForm.get(\'topicName\').hasError(\'required\')">\n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input style="padding-bottom: 24px;"\n formControlName="serviceAccountKey"\n [existingFileName]="pubSubConfigForm.get(\'serviceAccountKeyFileName\').value"\n (fileNameChanged)="pubSubConfigForm.get(\'serviceAccountKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.gcp-service-account-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" translate>tb.rulenode.message-attributes-hint</div>\n <tb-kv-map-config\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'<section [formGroup]="kafkaConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="kafkaConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.bootstrap-servers</mat-label>\n <input required matInput formControlName="bootstrapServers">\n <mat-error *ngIf="kafkaConfigForm.get(\'bootstrapServers\').hasError(\'required\')">\n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.retries</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="retries">\n <mat-error *ngIf="kafkaConfigForm.get(\'retries\').hasError(\'min\')">\n {{ \'tb.rulenode.min-retries-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.batch-size-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="batchSize">\n <mat-error *ngIf="kafkaConfigForm.get(\'batchSize\').hasError(\'min\')">\n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.linger-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="linger">\n <mat-error *ngIf="kafkaConfigForm.get(\'linger\').hasError(\'min\')">\n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.buffer-memory-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="bufferMemory">\n <mat-error *ngIf="kafkaConfigForm.get(\'bufferMemory\').hasError(\'min\')">\n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.acks</mat-label>\n <mat-select formControlName="acks" required>\n <mat-option *ngFor="let ackValue of ackValues" [value]="ackValue">\n {{ ackValue }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.key-serializer</mat-label>\n <input required matInput formControlName="keySerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'keySerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.value-serializer</mat-label>\n <input required matInput formControlName="valueSerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'valueSerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.other-properties</label>\n <tb-kv-map-config\n required="false"\n formControlName="otherProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allMqttCredentialsTypes=$,n.mqttCredentialsTypeTranslationsMap=_,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],username:[e&&e.credentials?e.credentials.username:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;switch(t){case"anonymous":e.credentials={type:t};break;case"basic":e.credentials={type:t,username:e.credentials.username,password:e.credentials.password};break;case"cert.PEM":delete e.credentials.username}return e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.mqttConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("username").setValidators([]),t.get("password").setValidators([]),t.get("caCert").setValidators([]),t.get("caCertFileName").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"anonymous":break;case"basic":t.get("username").setValidators([i.Validators.required]),t.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("caCert").setValidators([i.Validators.required]),t.get("caCertFileName").setValidators([i.Validators.required]),t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("username").updateValueAndValidity({emitEvent:e}),t.get("password").updateValueAndValidity({emitEvent:e}),t.get("caCert").updateValueAndValidity({emitEvent:e}),t.get("caCertFileName").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'<section [formGroup]="mqttConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="mqttConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.mqtt-topic-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <div fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="mqttConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.connect-timeout</mat-label>\n <input required type="number" step="1" min="1" max="200" matInput formControlName="connectTimeoutSec">\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'required\')">\n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'min\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'max\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.client-id</mat-label>\n <input matInput formControlName="clientId">\n </mat-form-field>\n <mat-checkbox formControlName="cleanSession" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.clean-session\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="ssl" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.enable-ssl\' | translate }}\n </mat-checkbox>\n <mat-expansion-panel class="tb-mqtt-credentials-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ mqttCredentialsTypeTranslationsMap.get(mqttConfigForm.get(\'credentials\').get(\'type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <section formGroupName="credentials" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allMqttCredentialsTypes" [value]="credentialsType">\n {{ mqttCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="mqttConfigForm.get(\'credentials\').get(\'type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="mqttConfigForm.get(\'credentials\').get(\'type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="basic">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input required matInput formControlName="username">\n <mat-error *ngIf="mqttConfigForm.get(\'credentials\').get(\'username\').hasError(\'required\')">\n {{ \'tb.rulenode.username-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" required matInput formControlName="password">\n <mat-error *ngIf="mqttConfigForm.get(\'credentials\').get(\'password\').hasError(\'required\')">\n {{ \'tb.rulenode.password-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="mqttConfigForm.get(\'credentials\').get(\'caCertFileName\').value"\n (fileNameChanged)="mqttConfigForm.get(\'credentials\').get(\'caCertFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="mqttConfigForm.get(\'credentials\').get(\'certFileName\').value"\n (fileNameChanged)="mqttConfigForm.get(\'credentials\').get(\'certFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="mqttConfigForm.get(\'credentials\').get(\'privateKeyFileName\').value"\n (fileNameChanged)="mqttConfigForm.get(\'credentials\').get(\'privateKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password">\n </mat-form-field>\n </ng-template>\n </section>\n </section>\n </mat-expansion-panel>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'<section [formGroup]="rabbitMqConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.exchange-name-pattern</mat-label>\n <input matInput formControlName="exchangeNamePattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.routing-key-pattern</mat-label>\n <input matInput formControlName="routingKeyPattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-properties</mat-label>\n <mat-select formControlName="messageProperties">\n <mat-option *ngFor="let property of messageProperties" [value]="property">\n {{ property }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.virtual-host</mat-label>\n <input matInput formControlName="virtualHost">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" matInput formControlName="password">\n </mat-form-field>\n <mat-checkbox formControlName="automaticRecoveryEnabled" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.connection-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.handshake-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="handshakeTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'handshakeTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.client-properties</label>\n <tb-kv-map-config\n required="false"\n formControlName="clientProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.httpRequestTypes=Object.keys(Q),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value;t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)]),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'<section [formGroup]="restApiCallConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.endpoint-url-pattern</mat-label>\n <input required matInput formControlName="restEndpointUrlPattern">\n <mat-error *ngIf="restApiCallConfigForm.get(\'restEndpointUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.endpoint-url-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-method</mat-label>\n <mat-select formControlName="requestMethod">\n <mat-option *ngFor="let requestType of httpRequestTypes" [value]="requestType">\n {{ requestType }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName="useSimpleClientHttpFactory" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n </mat-checkbox>\n <mat-form-field *ngIf="restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value === false" class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.read-timeout</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="readTimeoutMs">\n <mat-hint innerHTML="{{ \'tb.rulenode.read-timeout-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.max-parallel-requests-count</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxParallelRequestsCount">\n <mat-hint innerHTML="{{ \'tb.rulenode.max-parallel-requests-count-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.headers</label>\n <div class="tb-hint" translate>tb.rulenode.headers-hint</div>\n <tb-kv-map-config\n required="false"\n formControlName="headers"\n keyText="tb.rulenode.header"\n keyRequiredText="tb.rulenode.header-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n <mat-checkbox formControlName="useRedisQueueForMsgPersistence" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n </mat-checkbox>\n <div fxLayout="column" *ngIf="restApiCallConfigForm.get(\'useRedisQueueForMsgPersistence\').value === true">\n <mat-checkbox formControlName="trimQueue" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.redis-queue-max-size</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxQueueSize">\n </mat-form-field>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings"]},r.prototype.updateValidators=function(e){this.sendEmailConfigForm.get("useSystemSmtpSettings").value?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'<section [formGroup]="sendEmailConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useSystemSmtpSettings" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="sendEmailConfigForm.get(\'useSystemSmtpSettings\').value === false">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.smtp-protocol</mat-label>\n <mat-select formControlName="smtpProtocol">\n <mat-option *ngFor="let smtpProtocol of smtpProtocols" [value]="smtpProtocol">\n {{ smtpProtocol.toUpperCase() }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-host</mat-label>\n <input required matInput formControlName="smtpHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpHost\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="smtpPort">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'min\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'max\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.timeout-msec</mat-label>\n <input required type="number" step="1" min="0" matInput formControlName="timeout">\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox formControlName="enableTls" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.enable-tls\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" *ngIf="sendEmailConfigForm.get(\'enableTls\').value === true">\n <mat-label translate>tb.rulenode.tls-version</mat-label>\n <mat-select formControlName="tlsVersion">\n <mat-option *ngFor="let tlsVersion of tlsVersions" [value]="tlsVersion">\n {{ tlsVersion }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input matInput type="password" placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" formControlName="password">\n </mat-form-field>\n </section>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(){function e(){}return e=b([t.NgModule({declarations:[T,x,q,S,I,k,N,V,E,A,L,W,J,Y,Z,ae,oe,ie,le,se,me,ue,de,pe],imports:[r.CommonModule,a.SharedModule,ne],exports:[T,x,q,S,I,k,N,V,E,A,L,W,J,Y,Z,ae,oe,ie,le,se,me,ue,de,pe]})],e)}(),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'<section [formGroup]="checkMessageConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding tb-required">tb.rulenode.data-keys</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #messageNamesChipList>\n <mat-chip\n *ngFor="let messageName of checkMessageConfigForm.get(\'messageNames\').value;"\n (removed)="removeMessageName(messageName)">\n {{messageName}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.data-keys\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="messageNamesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addMessageName($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.separator-hint</div>\n <label translate class="tb-title no-padding tb-required">tb.rulenode.metadata-keys</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #metadataNamesChipList>\n <mat-chip\n *ngFor="let metadataName of checkMessageConfigForm.get(\'metadataNames\').value;"\n (removed)="removeMetadataName(metadataName)">\n {{metadataName}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.metadata-keys\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="metadataNamesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addMetadataName($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.separator-hint</div>\n <mat-checkbox fxFlex formControlName="checkAllKeys" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.check-all-keys\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.check-all-keys-hint</div>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'<section [formGroup]="checkRelationConfigForm" fxLayout="column">\n <mat-checkbox fxFlex formControlName="checkForSingleEntity" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.check-relation-hint</div>\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select formControlName="direction" required>\n <mat-option *ngFor="let direction of entitySearchDirection" [value]="direction">\n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout="row" *ngIf="checkRelationConfigForm.get(\'checkForSingleEntity\').value" style="padding-top: 20px">\n <tb-entity-type-select\n style="min-width: 100px; padding-bottom: 20px; padding-right: 8px;"\n showLabel\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <tb-entity-autocomplete\n fxFlex\n required\n *ngIf="checkRelationConfigForm.get(\'entityType\').value"\n [entityType]="checkRelationConfigForm.get(\'entityType\').value"\n formControlName="entityId">\n </tb-entity-autocomplete>\n </div>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'<section [formGroup]="geoFilterConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.latitude-key-name</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.longitude-key-name</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox fxFlex formControlName="fetchPerimeterInfoFromMessageMetadata" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n </mat-checkbox>\n <div fxLayout="row" *ngIf="!geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.perimeter-type</mat-label>\n <mat-select formControlName="perimeterType" required>\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-latitude</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-longitude</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range-units</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="row" *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="column" fxFlex="100">\n <mat-form-field class="mat-block" hintLabel="{{\'tb.rulenode.polygon-definition-hint\' | translate}}">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'<section [formGroup]="messageTypeConfigForm" fxLayout="column">\n <tb-message-types-config\n required\n label="tb.rulenode.message-types-filter"\n formControlName="messageTypes"\n ></tb-message-types-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'<section [formGroup]="originatorTypeConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding tb-required">tb.rulenode.originator-types-filter</label>\n <tb-entity-type-list fxFlex\n formControlName="originatorTypes"\n [allowedEntityTypes]="allowedEntityTypes"\n [ignoreAuthorityFilter]="true"\n required>\n </tb-entity-type-list>\n</section>\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'<section [formGroup]="scriptConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.filter</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-filter-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'<section [formGroup]="switchConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.switch</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-switch-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'<section [formGroup]="alarmStatusConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" class="alarm-status-list">\n <mat-label translate>tb.rulenode.alarm-status-filter</mat-label>\n <mat-chip-list #alarmStatusChipList required>\n <mat-chip\n *ngFor="let alarmStatus of alarmStatusConfigForm.get(\'alarmStatusList\').value;"\n (removed)="removeAlarmStatus(alarmStatus)">\n <span>\n <strong>{{alarmStatusTranslationsMap.get(alarmStatus) | translate}}</strong>\n </span>\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text"\n style="max-width: 200px;"\n #alarmStatusInput\n (focusin)="onAlarmStatusInputFocus()"\n [formControl]="statusFormControl"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="alarmStatusAutocomplete"\n [matChipInputFor]="alarmStatusChipList">\n </mat-chip-list>\n <mat-autocomplete #alarmStatusAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="alarmStatusSelected($event)"\n [displayWith]="displayStatusFn">\n <mat-option *ngFor="let status of filteredAlarmStatus | async" [value]="status">\n <span [innerHTML]="alarmStatusTranslationsMap.get(status) | translate | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredAlarmStatus | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div>\n <span translate>tb.rulenode.no-alarm-status-matching</span>\n </div>\n </div>\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n <tb-error [error]="(statusFormControl.touched &&\n alarmStatusConfigForm.get(\'alarmStatusList\').hasError(\'required\'))\n ? translate.instant(\'tb.rulenode.alarm-status-list-empty\') : \'\'"></tb-error>\n </section>\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(){function e(){}return e=b([t.NgModule({declarations:[fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,ne],exports:[fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'<section [formGroup]="customerAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.attr-mapping</label>\n <mat-checkbox fxFlex formControlName="telemetry" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n </mat-checkbox>\n <tb-kv-map-config\n required\n formControlName="attrMapping"\n requiredText="tb.rulenode.attr-mapping-required"\n keyText="{{ customerAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry\' : \'tb.rulenode.source-attribute\' }}"\n keyRequiredText="{{ customerAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry-required\' : \'tb.rulenode.source-attribute-required\' }}"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'<section [formGroup]="entityDetailsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" class="entity-fields-list">\n <mat-label translate>tb.rulenode.entity-details</mat-label>\n <mat-chip-list #detailsChipList required>\n <mat-chip\n *ngFor="let details of entityDetailsConfigForm.get(\'detailsList\').value;"\n (removed)="removeDetailsField(details)">\n <span>\n <strong>{{entityDetailsTranslationsMap.get(details) | translate}}</strong>\n </span>\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text"\n style="max-width: 200px;"\n #detailsInput\n (focusin)="onEntityDetailsInputFocus()"\n [formControl]="detailsFormControl"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="detailsAutocomplete"\n [matChipInputFor]="detailsChipList">\n </mat-chip-list>\n <mat-autocomplete #detailsAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="detailsFieldSelected($event)"\n [displayWith]="displayDetailsFn">\n <mat-option *ngFor="let details of filteredEntityDetails | async" [value]="details">\n <span [innerHTML]="entityDetailsTranslationsMap.get(details) | translate | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredEntityDetails | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div>\n <span translate>tb.rulenode.no-entity-details-matching</span>\n </div>\n </div>\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n <tb-error [error]="(detailsFormControl.touched &&\n entityDetailsConfigForm.get(\'detailsList\').hasError(\'required\'))\n ? translate.instant(\'tb.rulenode.entity-details-list-empty\') : \'\'"></tb-error>\n <mat-checkbox fxFlex formControlName="addToMetadata" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.add-to-metadata-hint</div>\n</section>\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'<section [formGroup]="deviceAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.device-relations-query</label>\n <tb-device-relations-query-config\n required\n formControlName="deviceRelationsQuery"\n style="padding-bottom: 15px;">\n </tb-device-relations-query-config>\n <mat-checkbox fxFlex formControlName="tellFailureIfAbsent" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.tell-failure-if-absent-hint</div>\n <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #clientAttributesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'clientAttributeNames\').value;"\n (removed)="removeKey(key, \'clientAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.client-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="clientAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'clientAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #sharedAttributesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'sharedAttributeNames\').value;"\n (removed)="removeKey(key, \'sharedAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="sharedAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'sharedAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #serverAttributesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'serverAttributeNames\').value;"\n (removed)="removeKey(key, \'serverAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.server-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="serverAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'serverAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #latestTimeseriesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'latestTsKeyNames\').value;"\n (removed)="removeKey(key, \'latestTsKeyNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="latestTimeseriesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'latestTsKeyNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <mat-checkbox formControlName="getLatestValueWithTs" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" innerHTML="{{ \'tb.rulenode.get-latest-value-with-ts-hint\' | translate }}"></div>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'<section [formGroup]="originatorAttributesConfigForm" fxLayout="column">\n <mat-checkbox fxFlex formControlName="tellFailureIfAbsent" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.tell-failure-if-absent-hint</div>\n <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #clientAttributesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'clientAttributeNames\').value;"\n (removed)="removeKey(key, \'clientAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.client-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="clientAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'clientAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #sharedAttributesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'sharedAttributeNames\').value;"\n (removed)="removeKey(key, \'sharedAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="sharedAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'sharedAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #serverAttributesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'serverAttributeNames\').value;"\n (removed)="removeKey(key, \'serverAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.server-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="serverAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'serverAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #latestTimeseriesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'latestTsKeyNames\').value;"\n (removed)="removeKey(key, \'latestTsKeyNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="latestTimeseriesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'latestTsKeyNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <mat-checkbox formControlName="getLatestValueWithTs" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" innerHTML="{{ \'tb.rulenode.get-latest-value-with-ts-hint\' | translate }}"></div>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'<section [formGroup]="originatorFieldsConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.source-field"\n keyRequiredText="tb.rulenode.source-field-required"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n.fetchMode=j,n.fetchModes=Object.keys(j),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===j.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'<section [formGroup]="getTelemetryFromDatabaseConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #latestTimeseriesChipList>\n <mat-chip\n *ngFor="let key of getTelemetryFromDatabaseConfigForm.get(\'latestTsKeyNames\').value;"\n (removed)="removeKey(key, \'latestTsKeyNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="latestTimeseriesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'latestTsKeyNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.fetch-mode</mat-label>\n <mat-select formControlName="fetchMode" required>\n <mat-option *ngFor="let mode of fetchModes" [value]="mode">\n {{ mode }}\n </mat-option>\n </mat-select>\n <mat-hint translate>tb.rulenode.fetch-mode-hint</mat-hint>\n </mat-form-field>\n <div fxLayout="column" *ngIf="getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value === fetchMode.ALL">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.order-by</mat-label>\n <mat-select formControlName="orderBy" required>\n <mat-option *ngFor="let order of samplingOrders" [value]="order">\n {{ order }}\n </mat-option>\n </mat-select>\n <mat-hint translate>tb.rulenode.order-by-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.limit</mat-label>\n <input type="number" min="2" max="1000" step="1" matInput formControlName="limit" required>\n <mat-hint translate>tb.rulenode.limit-hint</mat-hint>\n </mat-form-field>\n </div>\n <mat-checkbox formControlName="useMetadataIntervalPatterns">\n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.use-metadata-interval-patterns-hint</div>\n <div fxLayout="column" *ngIf="getTelemetryFromDatabaseConfigForm.get(\'useMetadataIntervalPatterns\').value === false; else intervalPattern">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.start-interval</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="startInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.start-interval-time-unit</mat-label>\n <mat-select formControlName="startIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.end-interval</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="endInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.end-interval-time-unit</mat-label>\n <mat-select formControlName="endIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n <ng-template #intervalPattern>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.start-interval-pattern</mat-label>\n <input matInput formControlName="startIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.start-interval-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.end-interval-pattern</mat-label>\n <input matInput formControlName="endIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.end-interval-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </ng-template>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'<section [formGroup]="relatedAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.relations-query</label>\n <tb-relations-query-config\n required\n formControlName="relationsQuery"\n style="padding-bottom: 15px;">\n </tb-relations-query-config>\n <label translate class="tb-title tb-required">tb.rulenode.attr-mapping</label>\n <mat-checkbox fxFlex formControlName="telemetry" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n </mat-checkbox>\n <tb-kv-map-config\n required\n formControlName="attrMapping"\n requiredText="tb.rulenode.attr-mapping-required"\n keyText="{{ relatedAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry\' : \'tb.rulenode.source-attribute\' }}"\n keyRequiredText="{{ relatedAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry-required\' : \'tb.rulenode.source-attribute-required\' }}"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'<section [formGroup]="tenantAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.attr-mapping</label>\n <mat-checkbox fxFlex formControlName="telemetry" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n </mat-checkbox>\n <tb-kv-map-config\n required\n formControlName="attrMapping"\n requiredText="tb.rulenode.attr-mapping-required"\n keyText="{{ tenantAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry\' : \'tb.rulenode.source-attribute\' }}"\n keyRequiredText="{{ tenantAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry-required\' : \'tb.rulenode.source-attribute-required\' }}"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[xe,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,ne],exports:[xe,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'<section [formGroup]="changeOriginatorConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.originator-source</mat-label>\n <mat-select formControlName="originatorSource" required>\n <mat-option *ngFor="let source of originatorSources" [value]="source">\n {{ originatorSourceTranslationMap.get(source) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <section fxLayout="column" *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === originatorSource.RELATED">\n <label translate class="tb-title tb-required">tb.rulenode.relations-query</label>\n <tb-relations-query-config\n required\n formControlName="relationsQuery"\n style="padding-bottom: 15px;">\n </tb-relations-query-config>\n </section>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'<section [formGroup]="scriptConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.transform</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Transform"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-transformer-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'<section [formGroup]="toEmailConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.from-template</mat-label>\n <textarea required matInput formControlName="fromTemplate" rows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'fromTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.from-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.from-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.to-template</mat-label>\n <textarea required matInput formControlName="toTemplate" rows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'toTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.to-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.mail-address-list-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.cc-template</mat-label>\n <textarea matInput formControlName="ccTemplate" rows="2"></textarea>\n <mat-hint innerHTML="{{ \'tb.rulenode.mail-address-list-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.bcc-template</mat-label>\n <textarea matInput formControlName="bccTemplate" rows="2"></textarea>\n <mat-hint innerHTML="{{ \'tb.rulenode.mail-address-list-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.subject-template</mat-label>\n <textarea required matInput formControlName="subjectTemplate" rows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'subjectTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.subject-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.subject-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.body-template</mat-label>\n <textarea required matInput formControlName="bodyTemplate" rows="6"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'bodyTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.body-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.body-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe],imports:[r.CommonModule,a.SharedModule,ne],exports:[Le,Me,Pe]})],e)}(),we=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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","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 <code>${metaKeyName}</code> to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","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 <code>${metaKeyName}</code> 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","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use <code>${metaKeyName}</code> 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","tls-version":"TLS version","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".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "&lcub;\\"ts\\":1574329385897,\\"value\\":42&rcub;"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[ce,Te,Ae,Re,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=we,e.ɵa=F,e.ɵb=ce,e.ɵba=ne,e.ɵbb=X,e.ɵbc=ee,e.ɵbd=te,e.ɵbe=re,e.ɵbf=Te,e.ɵbg=fe,e.ɵbh=ge,e.ɵbi=ye,e.ɵbj=be,e.ɵbk=he,e.ɵbl=Ce,e.ɵbm=ve,e.ɵbn=Fe,e.ɵbo=Ae,e.ɵbp=xe,e.ɵbq=qe,e.ɵbr=Se,e.ɵbs=Ie,e.ɵbt=ke,e.ɵbu=Ne,e.ɵbv=Ve,e.ɵbw=Ee,e.ɵbx=Re,e.ɵby=Le,e.ɵbz=Me,e.ɵc=T,e.ɵca=Pe,e.ɵd=x,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=W,e.ɵo=J,e.ɵp=Y,e.ɵq=Z,e.ɵr=ae,e.ɵs=oe,e.ɵt=ie,e.ɵu=le,e.ɵv=se,e.ɵw=me,e.ɵx=ue,e.ɵy=de,e.ɵz=pe,Object.defineProperty(e,"__esModule",{value:!0})})); 15 ***************************************************************************** */var g=function(e,t){return(g=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 y(e,t){function r(){this.constructor=e}g(e,t),e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}function b(e,t,r,n){var a,o=arguments.length,i=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(i=(o<3?a(i):o>3?a(t,r,i):a(t,r))||i);return o>3&&i&&Object.defineProperty(t,r,i),i}function h(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)}function C(e){var t="function"==typeof Symbol&&e[Symbol.iterator],r=0;return t?t.call(e):{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}}}var v,F=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.emptyConfigForm},r.prototype.onConfigurationSet=function(e){this.emptyConfigForm=this.fb.group({})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-node-empty-config",template:"<div></div>"}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),T=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.attributeScopes=Object.keys(a.AttributeScope),n.telemetryTypeTranslationsMap=a.telemetryTypeTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.attributesConfigForm},r.prototype.onConfigurationSet=function(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-attributes-config",template:'<section [formGroup]="attributesConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>attribute.attributes-scope</mat-label>\n <mat-select formControlName="scope" required>\n <mat-option *ngFor="let scope of attributeScopes" [value]="scope">\n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),x=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.timeseriesConfigForm},r.prototype.onConfigurationSet=function(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-timeseries-config",template:'<section [formGroup]="timeseriesConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.default-ttl</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="defaultTTL" required>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'required\')">\n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="timeseriesConfigForm.get(\'defaultTTL\').hasError(\'min\')">\n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),q=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcRequestConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-request-config",template:'<section [formGroup]="rpcRequestConfigForm" fxLayout="column">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.timeout-sec</mat-label>\n <input type="number" min="0" step="1" matInput formControlName="timeoutInSeconds" required>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rpcRequestConfigForm.get(\'timeoutInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),S=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.logConfigForm},r.prototype.onConfigurationSet=function(e){this.logConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.logConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.logConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-log-config",template:'<section [formGroup]="logConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.to-string</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="ToString"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-to-string-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),I=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.assignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-assign-to-customer-config",template:'<section [formGroup]="assignCustomerConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-checkbox fxFlex formControlName="createCustomerIfNotExists" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="customerCacheExpiration">\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="assignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),k=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.clearAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.clearAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],alarmType:[e?e.alarmType:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.clearAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-clear-alarm-config",template:'<section [formGroup]="clearAlarmConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.alarm-details-builder</label>\n <tb-js-func #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-details-function\' | translate }}\n </button>\n </div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="clearAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),N=function(e){function r(t,r,n,o){var i=e.call(this,t)||this;return i.store=t,i.fb=r,i.nodeScriptTestService=n,i.translate=o,i.alarmSeverities=Object.keys(a.AlarmSeverity),i.alarmSeverityTranslationMap=a.alarmSeverityTranslations,i.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],i}return y(r,e),r.prototype.configForm=function(){return this.createAlarmConfigForm},r.prototype.onConfigurationSet=function(e){this.createAlarmConfigForm=this.fb.group({alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[i.Validators.required]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]]})},r.prototype.validatorTriggers=function(){return["useMessageAlarmData"]},r.prototype.updateValidators=function(e){this.createAlarmConfigForm.get("useMessageAlarmData").value?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([i.Validators.required]),this.createAlarmConfigForm.get("severity").setValidators([i.Validators.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e})},r.prototype.testScript=function(){var e=this,t=this.createAlarmConfigForm.get("alarmDetailsBuildJs").value;this.nodeScriptTestService.testNodeScript(t,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.createAlarmConfigForm.get("alarmDetailsBuildJs").setValue(t)}))},r.prototype.removeKey=function(e,t){var r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.createAlarmConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.createAlarmConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-create-alarm-config",template:'<section [formGroup]="createAlarmConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.alarm-details-builder</label>\n <tb-js-func #jsFuncComponent\n formControlName="alarmDetailsBuildJs"\n functionName="Details"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-details-function\' | translate }}\n </button>\n </div>\n <mat-checkbox formControlName="useMessageAlarmData" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="createAlarmConfigForm.get(\'useMessageAlarmData\').value === false">\n <section fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.alarm-type</mat-label>\n <input required matInput formControlName="alarmType">\n <mat-error *ngIf="createAlarmConfigForm.get(\'alarmType\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.alarm-severity</mat-label>\n <mat-select formControlName="severity" required>\n <mat-option *ngFor="let severity of alarmSeverities" [value]="severity">\n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="createAlarmConfigForm.get(\'severity\').hasError(\'required\')">\n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </section>\n <mat-checkbox formControlName="propagate" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.propagate\' | translate }}\n </mat-checkbox>\n <section *ngIf="createAlarmConfigForm.get(\'propagate\').value === true">\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.relation-types-list</mat-label>\n <mat-chip-list #relationTypesChipList>\n <mat-chip\n *ngFor="let key of createAlarmConfigForm.get(\'relationTypes\').value;"\n (removed)="removeKey(key, \'relationTypes\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.relation-types-list\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="relationTypesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'relationTypes\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n <mat-hint innerHTML="{{ \'tb.rulenode.relation-types-list-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </section>\n </section>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),V=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.createRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[i.Validators.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["entityType"]},r.prototype.updateValidators=function(e){var t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==a.EntityType.DEVICE&&t!==a.EntityType.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([i.Validators.required]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-create-relation-config",template:'<section [formGroup]="createRelationConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout="row" fxLayoutGap="8px">\n <tb-entity-type-select\n showLabel\n style="min-width: 100px;"\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value" fxFlex class="mat-block" style="padding-bottom: 32px;">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="createRelationConfigForm.get(\'entityNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET"\n fxFlex class="mat-block" style="padding-bottom: 32px;">\n <mat-label translate>tb.rulenode.entity-type-pattern</mat-label>\n <input required matInput formControlName="entityTypePattern">\n <mat-error *ngIf="createRelationConfigForm.get(\'entityTypePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.relation-type-pattern</mat-label>\n <input required matInput formControlName="relationType">\n <mat-error *ngIf="createRelationConfigForm.get(\'relationType\').hasError(\'required\')">\n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.relation-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <section *ngIf="createRelationConfigForm.get(\'entityType\').value === entityType.CUSTOMER ||\n createRelationConfigForm.get(\'entityType\').value === entityType.DEVICE ||\n createRelationConfigForm.get(\'entityType\').value === entityType.ASSET">\n <mat-checkbox formControlName="createEntityIfNotExists">\n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.create-entity-if-not-exists-hint</div>\n </section>\n <mat-checkbox formControlName="removeCurrentRelations">\n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.remove-current-relations-hint</div>\n <mat-checkbox formControlName="changeOriginatorToRelatedEntity">\n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.change-originator-to-related-entity-hint</div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.entity-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="entityCacheExpiration">\n <mat-error *ngIf="createRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="createRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),E=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgDelayConfigForm},r.prototype.onConfigurationSet=function(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(1e5)]]})},r.prototype.validatorTriggers=function(){return["useMetadataPeriodInSecondsPatterns"]},r.prototype.updateValidators=function(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([i.Validators.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([i.Validators.required,i.Validators.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-delay-config",template:'<section [formGroup]="msgDelayConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useMetadataPeriodInSecondsPatterns">\n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.use-metadata-period-in-seconds-patterns-hint</div>\n <mat-form-field *ngIf="msgDelayConfigForm.get(\'useMetadataPeriodInSecondsPatterns\').value !== true; else periodInSecondsPattern"\n class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <ng-template #periodInSecondsPattern>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.period-in-seconds-pattern</mat-label>\n <input required matInput formControlName="periodInSecondsPattern">\n <mat-error *ngIf="msgDelayConfigForm.get(\'periodInSecondsPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.period-in-seconds-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </ng-template>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.max-pending-messages</mat-label>\n <input required type="number" min="1" max="100000" step="1" matInput formControlName="maxPendingMsgs">\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'required\')">\n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'min\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgDelayConfigForm.get(\'maxPendingMsgs\').hasError(\'max\')">\n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),A=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n}return y(r,e),r.prototype.configForm=function(){return this.deleteRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[i.Validators.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[i.Validators.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.prototype.validatorTriggers=function(){return["deleteForSingleEntity","entityType"]},r.prototype.updateValidators=function(e){var t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([i.Validators.required]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-delete-relation-config",template:'<section [formGroup]="deleteRelationConfigForm" fxLayout="column">\n <mat-checkbox formControlName="deleteForSingleEntity">\n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.delete-relation-hint</div>\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div *ngIf="deleteRelationConfigForm.get(\'deleteForSingleEntity\').value" fxLayout="row" fxLayoutGap="8px">\n <tb-entity-type-select\n showLabel\n style="min-width: 100px;"\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <mat-form-field *ngIf="deleteRelationConfigForm.get(\'entityType\').value" fxFlex class="mat-block" style="padding-bottom: 32px;">\n <mat-label translate>tb.rulenode.entity-name-pattern</mat-label>\n <input required matInput formControlName="entityNamePattern">\n <mat-error *ngIf="deleteRelationConfigForm.get(\'entityNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.relation-type-pattern</mat-label>\n <input required matInput formControlName="relationType">\n <mat-error *ngIf="deleteRelationConfigForm.get(\'relationType\').hasError(\'required\')">\n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.relation-type-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.entity-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="entityCacheExpiration">\n <mat-error *ngIf="deleteRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="deleteRelationConfigForm.get(\'entityCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.entity-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),L=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.generatorConfigForm},r.prototype.onConfigurationSet=function(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[i.Validators.required,i.Validators.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[i.Validators.required,i.Validators.min(1)]],originator:[e?e.originator:null,[]],jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.prepareInputConfig=function(e){return e&&(e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e},r.prototype.prepareOutputConfig=function(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e},r.prototype.testScript=function(){var e=this,t=this.generatorConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId).subscribe((function(t){t&&e.generatorConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-action-node-generator-config",template:'<section [formGroup]="generatorConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-count</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="msgCount">\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'required\')">\n {{ \'tb.rulenode.message-count-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'msgCount\').hasError(\'min\')">\n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.period-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="periodInSeconds">\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'required\')">\n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="generatorConfigForm.get(\'periodInSeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <div fxLayout="column">\n <label class="tb-small">{{ \'tb.rulenode.originator\' | translate }}</label>\n <tb-entity-select\n required="false"\n formControlName="originator">\n </tb-entity-select>\n </div>\n <label translate class="tb-title no-padding">tb.rulenode.generate</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Generate"\n [functionArgs]="[\'prevMsg\', \'prevMetadata\', \'prevMsgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row" style="padding-bottom: 16px;">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-generator-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent);!function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR"}(v||(v={}));var M,P=new Map([[v.CUSTOMER,"tb.rulenode.originator-customer"],[v.TENANT,"tb.rulenode.originator-tenant"],[v.RELATED,"tb.rulenode.originator-related"],[v.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"]]);!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(M||(M={}));var R,w=new Map([[M.CIRCLE,"tb.rulenode.perimeter-circle"],[M.POLYGON,"tb.rulenode.perimeter-polygon"]]);!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(R||(R={}));var D,O=new Map([[R.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[R.SECONDS,"tb.rulenode.time-unit-seconds"],[R.MINUTES,"tb.rulenode.time-unit-minutes"],[R.HOURS,"tb.rulenode.time-unit-hours"],[R.DAYS,"tb.rulenode.time-unit-days"]]);!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(D||(D={}));var K,B=new Map([[D.METER,"tb.rulenode.range-unit-meter"],[D.KILOMETER,"tb.rulenode.range-unit-kilometer"],[D.FOOT,"tb.rulenode.range-unit-foot"],[D.MILE,"tb.rulenode.range-unit-mile"],[D.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);!function(e){e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(K||(K={}));var j,U,G,H=new Map([[K.TITLE,"tb.rulenode.entity-details-title"],[K.COUNTRY,"tb.rulenode.entity-details-country"],[K.STATE,"tb.rulenode.entity-details-state"],[K.ZIP,"tb.rulenode.entity-details-zip"],[K.ADDRESS,"tb.rulenode.entity-details-address"],[K.ADDRESS2,"tb.rulenode.entity-details-address2"],[K.PHONE,"tb.rulenode.entity-details-phone"],[K.EMAIL,"tb.rulenode.entity-details-email"],[K.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(j||(j={})),function(e){e.ASC="ASC",e.DESC="DESC"}(U||(U={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(G||(G={}));var Q,z=new Map([[G.STANDARD,"tb.rulenode.sqs-queue-standard"],[G.FIFO,"tb.rulenode.sqs-queue-fifo"]]),$=["anonymous","basic","cert.PEM"],_=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]);!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Q||(Q={}));var W=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.geoActionConfigForm},r.prototype.onConfigurationSet=function(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[i.Validators.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterType").setValidators([]):this.geoActionConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoActionConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoActionConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-gps-geofencing-config",template:'<section [formGroup]="geoActionConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.latitude-key-name</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.longitude-key-name</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox fxFlex formControlName="fetchPerimeterInfoFromMessageMetadata" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n </mat-checkbox>\n <div fxLayout="row" *ngIf="!geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.perimeter-type</mat-label>\n <mat-select formControlName="perimeterType" required>\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column"\n *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-latitude</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-longitude</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range-units</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="column" *ngIf="geoActionConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoActionConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field class="mat-block" hintLabel="{{\'tb.rulenode.polygon-definition-hint\' | translate}}" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minInsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minInsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-inside-duration-time-unit</mat-label>\n <mat-select formControlName="minInsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="minOutsideDuration" required>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'required\')">\n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="geoActionConfigForm.get(\'minOutsideDuration\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.min-outside-duration-time-unit</mat-label>\n <mat-select formControlName="minOutsideDurationTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),J=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.msgCountConfigForm},r.prototype.onConfigurationSet=function(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[i.Validators.required,i.Validators.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-msg-count-config",template:'<section [formGroup]="msgCountConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.interval-seconds</mat-label>\n <input required type="number" min="1" step="1" matInput formControlName="interval">\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'required\')">\n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="msgCountConfigForm.get(\'interval\').hasError(\'min\')">\n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.output-timeseries-key-prefix</mat-label>\n <input required matInput formControlName="telemetryPrefix">\n <mat-error *ngIf="msgCountConfigForm.get(\'telemetryPrefix\').hasError(\'required\')">\n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Y=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.rpcReplyConfigForm},r.prototype.onConfigurationSet=function(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rpc-reply-config",template:'<section [formGroup]="rpcReplyConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-id-metadata-attribute</mat-label>\n <input matInput formControlName="requestIdMetaDataAttribute">\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Z=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.saveToCustomTableConfigForm},r.prototype.onConfigurationSet=function(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[i.Validators.required]],fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-custom-table-config",template:'<section [formGroup]="saveToCustomTableConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.custom-table-name</mat-label>\n <input required matInput formControlName="tableName">\n <mat-error *ngIf="saveToCustomTableConfigForm.get(\'tableName\').hasError(\'required\')">\n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.custom-table-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.message-field"\n keyRequiredText="tb.rulenode.message-field-required"\n valText="tb.rulenode.table-col"\n valRequiredText="tb.rulenode.table-col-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),X=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.translate=r,o.injector=n,o.fb=a,o.propagateChange=null,o.valueChangeSubscription=null,o}var a;return y(r,e),a=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){this.ngControl=this.injector.get(i.NgControl),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))},r.prototype.keyValsFormArray=function(){return this.kvListFormGroup.get("keyVals")},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t,r,n=this;this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();var a=[];if(e)try{for(var o=C(Object.keys(e)),l=o.next();!l.done;l=o.next()){var s=l.value;Object.prototype.hasOwnProperty.call(e,s)&&a.push(this.fb.group({key:[s,[i.Validators.required]],value:[e[s],[i.Validators.required]]}))}}catch(e){t={error:e}}finally{try{l&&!l.done&&(r=o.return)&&r.call(o)}finally{if(t)throw t.error}}this.kvListFormGroup.setControl("keyVals",this.fb.array(a)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((function(){n.updateModel()}))},r.prototype.removeKeyVal=function(e){this.kvListFormGroup.get("keyVals").removeAt(e)},r.prototype.addKeyVal=function(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[i.Validators.required]],value:["",[i.Validators.required]]}))},r.prototype.validate=function(e){return!this.kvListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.kvListFormGroup.valid?null:{kvFieldsRequired:!0}},r.prototype.updateModel=function(){var e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{var t={};e.forEach((function(e){t[e.key]=e.value})),this.propagateChange(t)}},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:t.Injector},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",String)],r.prototype,"requiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"keyRequiredText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valText",void 0),b([t.Input(),h("design:type",String)],r.prototype,"valRequiredText",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=a=b([t.Component({selector:"tb-kv-map-config",template:'<section fxLayout="column" class="tb-kv-map-config" [formGroup]="kvListFormGroup">\n <div class="header" fxFlex fxLayout="row" fxLayoutGap="8px">\n <span class="cell" fxFlex translate>{{ keyText }}</span>\n <span class="cell" fxFlex translate>{{ valText }}</span>\n <span [fxShow]="!disabled" style="width: 52px;" innerHTML="&nbsp"></span>\n </div>\n <div class="body">\n <div class="row" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"\n formArrayName="keyVals"\n *ngFor="let keyValControl of keyValsFormArray().controls; let $index = index">\n <mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="cell mat-block">\n <mat-label></mat-label>\n <input [formControl]="keyValControl.get(\'key\')" matInput required\n placeholder="{{ keyText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'key\').hasError(\'required\')">\n {{ keyRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" hideRequiredMarker class="cell mat-block">\n <mat-label></mat-label>\n <input [formControl]="keyValControl.get(\'value\')" matInput required\n placeholder="{{ valText | translate }}"/>\n <mat-error *ngIf="keyValControl.get(\'value\').hasError(\'required\')">\n {{ valRequiredText | translate }}\n </mat-error>\n </mat-form-field>\n <button mat-button mat-icon-button color="primary"\n [fxShow]="!disabled"\n type="button"\n (click)="removeKeyVal($index)"\n [disabled]="isLoading$ | async"\n matTooltip="{{ \'tb.key-val.remove-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n <tb-error [error]="ngControl.hasError(\'kvMapRequired\')\n ? translate.instant(requiredText) : \'\'"></tb-error>\n <div style="margin-top: 8px;">\n <button mat-button mat-raised-button color="primary"\n [fxShow]="!disabled"\n [disabled]="isLoading$ | async"\n (click)="addKeyVal()"\n type="button"\n matTooltip="{{ \'tb.key-val.add-entry\' | translate }}"\n matTooltipPosition="above">\n <mat-icon>add</mat-icon>\n {{ \'action.add\' | translate }}\n </button>\n </div>\n</section>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return a})),multi:!0},{provide:i.NG_VALIDATORS,useExisting:t.forwardRef((function(){return a})),multi:!0}],styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .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}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:20px;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .row{padding-top:5px;max-height:40px}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell{margin:0;max-height:40px}:host ::ng-deep .tb-kv-map-config .body mat-form-field.cell .mat-form-field-infix{border-top:0}:host ::ng-deep .tb-kv-map-config .body button.mat-button{margin:0}"]}),h("design:paramtypes",[o.Store,n.TranslateService,t.Injector,i.FormBuilder])],r)}(a.PageComponent),ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.entityType=a.EntityType,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[i.Validators.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((function(t){e.deviceRelationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-device-relations-query-config",template:'<section fxLayout="column" [formGroup]="deviceRelationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly" style="padding-bottom: 16px;">\n {{ \'relation.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: rgba(0,0,0,0.57);" translate>relation.relation-type</div>\n <tb-relation-type-autocomplete\n fxFlex\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n <div class="mat-caption tb-required" style="color: rgba(0,0,0,0.57);" translate>device.device-types</div>\n <tb-entity-subtype-list\n required\n [entityType]="entityType.DEVICE"\n formControlName="deviceTypes">\n </tb-entity-subtype-list>\n</section>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),te=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.directionTypes=Object.keys(a.EntitySearchDirection),n.directionTypeTranslations=a.entitySearchDirectionTranslations,n.propagateChange=null,n}var n;return y(r,e),n=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.ngOnInit=function(){var e=this;this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[i.Validators.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((function(t){e.relationsQueryFormGroup.valid?e.propagateChange(t):e.propagateChange(null)}))},r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})},r.prototype.writeValue=function(e){this.relationsQueryFormGroup.reset(e,{emitEvent:!1})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),r=n=b([t.Component({selector:"tb-relations-query-config",template:'<section fxLayout="column" [formGroup]="relationsQueryFormGroup">\n <mat-checkbox formControlName="fetchLastLevelOnly" style="padding-bottom: 16px;">\n {{ \'relation.last-level-relation\' | translate }}\n </mat-checkbox>\n <div fxLayoutGap="8px" fxLayout="row">\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select required matInput formControlName="direction">\n <mat-option *ngFor="let type of directionTypes" [value]="type">\n {{ directionTypeTranslations.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field fxFlex floatLabel="always" class="mat-block">\n <mat-label translate>tb.rulenode.max-relation-level</mat-label>\n <input matInput\n type="number"\n min="1"\n step="1"\n placeholder="{{ \'tb.rulenode.unlimited-level\' | translate }}"\n formControlName="maxLevel">\n </mat-form-field>\n </div>\n <div class="mat-caption" style="color: rgba(0,0,0,0.57);" translate>relation.relation-filters</div>\n <tb-relation-filters\n formControlName="filters"\n ></tb-relation-filters>\n</section>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return n})),multi:!0}]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.PageComponent),re=function(e){function r(t,r,n,o){var i,l,m=e.call(this,t)||this;m.store=t,m.translate=r,m.truncate=n,m.fb=o,m.placeholder="tb.rulenode.message-type",m.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],m.messageTypes=[],m.messageTypesList=[],m.searchText="",m.propagateChange=function(e){},m.messageTypeConfigForm=m.fb.group({messageType:[null]});try{for(var u=C(Object.keys(a.MessageType)),d=u.next();!d.done;d=u.next()){var p=d.value;m.messageTypesList.push({name:a.messageTypeNames.get(a.MessageType[p]),value:p})}}catch(e){i={error:e}}finally{try{d&&!d.done&&(l=u.return)&&l.call(u)}finally{if(i)throw i.error}}return m}var l;return y(r,e),l=r,Object.defineProperty(r.prototype,"required",{get:function(){return this.requiredValue},set:function(e){this.requiredValue=u.coerceBooleanProperty(e)},enumerable:!0,configurable:!0}),r.prototype.registerOnChange=function(e){this.propagateChange=e},r.prototype.registerOnTouched=function(e){},r.prototype.ngOnInit=function(){var e=this;this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(t){return e.fetchMessageTypes(t)})),f.share())},r.prototype.ngAfterViewInit=function(){},r.prototype.setDisabledState=function(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})},r.prototype.writeValue=function(e){var t=this;this.searchText="",this.messageTypes.length=0,e&&e.forEach((function(e){var r=t.messageTypesList.find((function(t){return t.value===e}));r?t.messageTypes.push({name:r.name,value:r.value}):t.messageTypes.push({name:e,value:e})}))},r.prototype.displayMessageTypeFn=function(e){return e?e.name:void 0},r.prototype.textIsNotEmpty=function(e){return!!(e&&null!=e&&e.length>0)},r.prototype.createMessageType=function(e,t){e.preventDefault(),this.transformMessageType(t)},r.prototype.add=function(e){this.transformMessageType(e.value)},r.prototype.fetchMessageTypes=function(e){if(this.searchText=e,this.searchText&&this.searchText.length){var t=this.searchText.toUpperCase();return c.of(this.messageTypesList.filter((function(e){return e.name.toUpperCase().includes(t)})))}return c.of(this.messageTypesList)},r.prototype.transformMessageType=function(e){if((e||"").trim()){var t=null,r=e.trim(),n=this.messageTypesList.find((function(e){return e.name===r}));(t=n?{name:n.name,value:n.value}:{name:r,value:r})&&this.addMessageType(t)}this.clear("")},r.prototype.remove=function(e){var t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())},r.prototype.selected=function(e){this.addMessageType(e.option.value),this.clear("")},r.prototype.addMessageType=function(e){-1===this.messageTypes.findIndex((function(t){return t.value===e.value}))&&(this.messageTypes.push(e),this.updateModel())},r.prototype.onFocus=function(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((function(){t.messageTypeInput.nativeElement.blur(),t.messageTypeInput.nativeElement.focus()}),0)},r.prototype.updateModel=function(){var e=this.messageTypes.map((function(e){return e.value}));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:a.TruncatePipe},{type:i.FormBuilder}]},b([t.Input(),h("design:type",Boolean),h("design:paramtypes",[Boolean])],r.prototype,"required",null),b([t.Input(),h("design:type",String)],r.prototype,"label",void 0),b([t.Input(),h("design:type",Object)],r.prototype,"placeholder",void 0),b([t.Input(),h("design:type",Boolean)],r.prototype,"disabled",void 0),b([t.ViewChild("chipList",{static:!1}),h("design:type",d.MatChipList)],r.prototype,"chipList",void 0),b([t.ViewChild("messageTypeAutocomplete",{static:!1}),h("design:type",p.MatAutocomplete)],r.prototype,"matAutocomplete",void 0),b([t.ViewChild("messageTypeInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"messageTypeInput",void 0),r=l=b([t.Component({selector:"tb-message-types-config",template:'<mat-form-field [formGroup]="messageTypeConfigForm" style="width: 100%;">\n <mat-label *ngIf="label" translate>{{ label }}</mat-label>\n <mat-chip-list #chipList [required]="required">\n <mat-chip\n *ngFor="let messageType of messageTypes"\n [selectable]="true"\n [removable]="true"\n (removed)="remove(messageType)">\n {{messageType.name}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{ placeholder | translate }}"\n style="max-width: 200px;"\n #messageTypeInput\n (focusin)="onFocus()"\n formControlName="messageType"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="messageTypeAutocomplete"\n [matChipInputFor]="chipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="add($event)">\n </mat-chip-list>\n <mat-autocomplete #messageTypeAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="selected($event)"\n [displayWith]="displayMessageTypeFn">\n <mat-option *ngFor="let messageType of filteredMessageTypes | async" [value]="messageType">\n <span [innerHTML]="messageType.name | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredMessageTypes | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">\n <span translate>tb.rulenode.no-message-types-found</span>\n </div>\n <ng-template #searchNotEmpty>\n <span>\n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, &apos;...&apos;)}) | async }}\n </span>\n </ng-template>\n <span>\n <a translate (click)="createMessageType($event, searchText)">tb.rulenode.create-new-message-type</a>\n </span>\n </div>\n </mat-option>\n </mat-autocomplete>\n <mat-error *ngIf="chipList.errorState">\n {{ \'tb.rulenode.message-types-required\' | translate }}\n </mat-error>\n</mat-form-field>\n',providers:[{provide:i.NG_VALUE_ACCESSOR,useExisting:t.forwardRef((function(){return l})),multi:!0}]}),h("design:paramtypes",[o.Store,n.TranslateService,a.TruncatePipe,i.FormBuilder])],r)}(a.PageComponent),ne=function(){function e(){}return e=b([t.NgModule({declarations:[X,ee,te,re],imports:[r.CommonModule,a.SharedModule,m.HomeComponentsModule],exports:[X,ee,te,re]})],e)}(),ae=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.unassignCustomerConfigForm},r.prototype.onConfigurationSet=function(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[i.Validators.required]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[i.Validators.required,i.Validators.min(0)]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-un-assign-to-customer-config",template:'<section [formGroup]="unassignCustomerConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-name-pattern</mat-label>\n <input required matInput formControlName="customerNamePattern">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerNamePattern\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-name-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.customer-cache-expiration</mat-label>\n <input required type="number" min="0" step="1" matInput formControlName="customerCacheExpiration">\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'required\')">\n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="unassignCustomerConfigForm.get(\'customerCacheExpiration\').hasError(\'min\')">\n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.customer-cache-expiration-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),oe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.snsConfigForm},r.prototype.onConfigurationSet=function(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[i.Validators.required]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sns-config",template:'<section [formGroup]="snsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.topic-arn-pattern</mat-label>\n <input required matInput formControlName="topicArnPattern">\n <mat-error *ngIf="snsConfigForm.get(\'topicArnPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.topic-arn-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="snsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="snsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="snsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.sqsQueueType=G,n.sqsQueueTypes=Object.keys(G),n.sqsQueueTypeTranslationsMap=z,n}return y(r,e),r.prototype.configForm=function(){return this.sqsConfigForm},r.prototype.onConfigurationSet=function(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[i.Validators.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[i.Validators.required]],delaySeconds:[e?e.delaySeconds:null,[i.Validators.min(0),i.Validators.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[i.Validators.required]],secretAccessKey:[e?e.secretAccessKey:null,[i.Validators.required]],region:[e?e.region:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-sqs-config",template:'<section [formGroup]="sqsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.queue-type</mat-label>\n <mat-select formControlName="queueType" required>\n <mat-option *ngFor="let type of sqsQueueTypes" [value]="type">\n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.queue-url-pattern</mat-label>\n <input required matInput formControlName="queueUrlPattern">\n <mat-error *ngIf="sqsConfigForm.get(\'queueUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.queue-url-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field *ngIf="sqsConfigForm.get(\'queueType\').value === sqsQueueType.STANDARD" class="mat-block">\n <mat-label translate>tb.rulenode.delay-seconds</mat-label>\n <input required type="number" min="0" max="900" step="1" matInput formControlName="delaySeconds">\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'min\')">\n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n </mat-error>\n <mat-error *ngIf="sqsConfigForm.get(\'delaySeconds\').hasError(\'max\')">\n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" translate>tb.rulenode.message-attributes-hint</div>\n <tb-kv-map-config\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-access-key-id</mat-label>\n <input required matInput formControlName="accessKeyId">\n <mat-error *ngIf="sqsConfigForm.get(\'accessKeyId\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-secret-access-key</mat-label>\n <input required matInput formControlName="secretAccessKey">\n <mat-error *ngIf="sqsConfigForm.get(\'secretAccessKey\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.aws-region</mat-label>\n <input required matInput formControlName="region">\n <mat-error *ngIf="sqsConfigForm.get(\'region\').hasError(\'required\')">\n {{ \'tb.rulenode.aws-region-required\' | translate }}\n </mat-error>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.pubSubConfigForm},r.prototype.onConfigurationSet=function(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[i.Validators.required]],topicName:[e?e.topicName:null,[i.Validators.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[i.Validators.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[i.Validators.required]],messageAttributes:[e?e.messageAttributes:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-pub-sub-config",template:'<section [formGroup]="pubSubConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.gcp-project-id</mat-label>\n <input required matInput formControlName="projectId">\n <mat-error *ngIf="pubSubConfigForm.get(\'projectId\').hasError(\'required\')">\n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.pubsub-topic-name</mat-label>\n <input required matInput formControlName="topicName">\n <mat-error *ngIf="pubSubConfigForm.get(\'topicName\').hasError(\'required\')">\n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <tb-file-input style="padding-bottom: 24px;"\n formControlName="serviceAccountKey"\n [existingFileName]="pubSubConfigForm.get(\'serviceAccountKeyFileName\').value"\n (fileNameChanged)="pubSubConfigForm.get(\'serviceAccountKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.gcp-service-account-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <label translate class="tb-title">tb.rulenode.message-attributes</label>\n <div class="tb-hint" translate>tb.rulenode.message-attributes-hint</div>\n <tb-kv-map-config\n required="false"\n formControlName="messageAttributes"\n keyText="tb.rulenode.name"\n keyRequiredText="tb.rulenode.name-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.ackValues=["all","-1","0","1"],n}return y(r,e),r.prototype.configForm=function(){return this.kafkaConfigForm},r.prototype.onConfigurationSet=function(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],bootstrapServers:[e?e.bootstrapServers:null,[i.Validators.required]],retries:[e?e.retries:null,[i.Validators.min(0)]],batchSize:[e?e.batchSize:null,[i.Validators.min(0)]],linger:[e?e.linger:null,[i.Validators.min(0)]],bufferMemory:[e?e.bufferMemory:null,[i.Validators.min(0)]],acks:[e?e.acks:null,[i.Validators.required]],keySerializer:[e?e.keySerializer:null,[i.Validators.required]],valueSerializer:[e?e.valueSerializer:null,[i.Validators.required]],otherProperties:[e?e.otherProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-kafka-config",template:'<section [formGroup]="kafkaConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="kafkaConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.bootstrap-servers</mat-label>\n <input required matInput formControlName="bootstrapServers">\n <mat-error *ngIf="kafkaConfigForm.get(\'bootstrapServers\').hasError(\'required\')">\n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.retries</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="retries">\n <mat-error *ngIf="kafkaConfigForm.get(\'retries\').hasError(\'min\')">\n {{ \'tb.rulenode.min-retries-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.batch-size-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="batchSize">\n <mat-error *ngIf="kafkaConfigForm.get(\'batchSize\').hasError(\'min\')">\n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.linger-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="linger">\n <mat-error *ngIf="kafkaConfigForm.get(\'linger\').hasError(\'min\')">\n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.buffer-memory-bytes</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="bufferMemory">\n <mat-error *ngIf="kafkaConfigForm.get(\'bufferMemory\').hasError(\'min\')">\n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.acks</mat-label>\n <mat-select formControlName="acks" required>\n <mat-option *ngFor="let ackValue of ackValues" [value]="ackValue">\n {{ ackValue }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.key-serializer</mat-label>\n <input required matInput formControlName="keySerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'keySerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.value-serializer</mat-label>\n <input required matInput formControlName="valueSerializer">\n <mat-error *ngIf="kafkaConfigForm.get(\'valueSerializer\').hasError(\'required\')">\n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.other-properties</label>\n <tb-kv-map-config\n required="false"\n formControlName="otherProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),me=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allMqttCredentialsTypes=$,n.mqttCredentialsTypeTranslationsMap=_,n}return y(r,e),r.prototype.configForm=function(){return this.mqttConfigForm},r.prototype.onConfigurationSet=function(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[i.Validators.required]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(200)]],clientId:[e?e.clientId:null,[]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[i.Validators.required]],username:[e&&e.credentials?e.credentials.username:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]]})})},r.prototype.prepareOutputConfig=function(e){var t=e.credentials.type;switch(t){case"anonymous":e.credentials={type:t};break;case"basic":e.credentials={type:t,username:e.credentials.username,password:e.credentials.password};break;case"cert.PEM":delete e.credentials.username}return e},r.prototype.validatorTriggers=function(){return["credentials.type"]},r.prototype.updateValidators=function(e){var t=this.mqttConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("username").setValidators([]),t.get("password").setValidators([]),t.get("caCert").setValidators([]),t.get("caCertFileName").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"anonymous":break;case"basic":t.get("username").setValidators([i.Validators.required]),t.get("password").setValidators([i.Validators.required]);break;case"cert.PEM":t.get("caCert").setValidators([i.Validators.required]),t.get("caCertFileName").setValidators([i.Validators.required]),t.get("privateKey").setValidators([i.Validators.required]),t.get("privateKeyFileName").setValidators([i.Validators.required]),t.get("cert").setValidators([i.Validators.required]),t.get("certFileName").setValidators([i.Validators.required])}t.get("username").updateValueAndValidity({emitEvent:e}),t.get("password").updateValueAndValidity({emitEvent:e}),t.get("caCert").updateValueAndValidity({emitEvent:e}),t.get("caCertFileName").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-mqtt-config",template:'<section [formGroup]="mqttConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.topic-pattern</mat-label>\n <input required matInput formControlName="topicPattern">\n <mat-error *ngIf="mqttConfigForm.get(\'topicPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.mqtt-topic-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <div fxFlex fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="mqttConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="40" class="mat-block">\n <mat-label translate>tb.rulenode.connect-timeout</mat-label>\n <input required type="number" step="1" min="1" max="200" matInput formControlName="connectTimeoutSec">\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'required\')">\n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'min\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="mqttConfigForm.get(\'connectTimeoutSec\').hasError(\'max\')">\n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.client-id</mat-label>\n <input matInput formControlName="clientId">\n </mat-form-field>\n <mat-checkbox formControlName="cleanSession" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.clean-session\' | translate }}\n </mat-checkbox>\n <mat-checkbox formControlName="ssl" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.enable-ssl\' | translate }}\n </mat-checkbox>\n <mat-expansion-panel class="tb-mqtt-credentials-panel-group">\n <mat-expansion-panel-header>\n <mat-panel-title translate>tb.rulenode.credentials</mat-panel-title>\n <mat-panel-description>\n {{ mqttCredentialsTypeTranslationsMap.get(mqttConfigForm.get(\'credentials\').get(\'type\').value) | translate }}\n </mat-panel-description>\n </mat-expansion-panel-header>\n <section formGroupName="credentials" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.credentials-type</mat-label>\n <mat-select formControlName="type" required>\n <mat-option *ngFor="let credentialsType of allMqttCredentialsTypes" [value]="credentialsType">\n {{ mqttCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n </mat-option>\n </mat-select>\n <mat-error *ngIf="mqttConfigForm.get(\'credentials\').get(\'type\').hasError(\'required\')">\n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <section fxLayout="column" [ngSwitch]="mqttConfigForm.get(\'credentials\').get(\'type\').value">\n <ng-template ngSwitchCase="anonymous">\n </ng-template>\n <ng-template ngSwitchCase="basic">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input required matInput formControlName="username">\n <mat-error *ngIf="mqttConfigForm.get(\'credentials\').get(\'username\').hasError(\'required\')">\n {{ \'tb.rulenode.username-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" required matInput formControlName="password">\n <mat-error *ngIf="mqttConfigForm.get(\'credentials\').get(\'password\').hasError(\'required\')">\n {{ \'tb.rulenode.password-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </ng-template>\n <ng-template ngSwitchCase="cert.PEM">\n <tb-file-input formControlName="caCert"\n inputId="caCertSelect"\n [existingFileName]="mqttConfigForm.get(\'credentials\').get(\'caCertFileName\').value"\n (fileNameChanged)="mqttConfigForm.get(\'credentials\').get(\'caCertFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.ca-cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input formControlName="cert"\n inputId="CertSelect"\n [existingFileName]="mqttConfigForm.get(\'credentials\').get(\'certFileName\').value"\n (fileNameChanged)="mqttConfigForm.get(\'credentials\').get(\'certFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.cert\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <tb-file-input style="padding-bottom: 8px;"\n formControlName="privateKey"\n inputId="privateKeySelect"\n [existingFileName]="mqttConfigForm.get(\'credentials\').get(\'privateKeyFileName\').value"\n (fileNameChanged)="mqttConfigForm.get(\'credentials\').get(\'privateKeyFileName\').setValue($event)"\n required\n requiredAsError\n label="{{\'tb.rulenode.private-key\' | translate}}"\n noFileText="tb.rulenode.no-file"\n dropLabel="{{\'tb.rulenode.drop-file\' | translate}}">\n </tb-file-input>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.private-key-password</mat-label>\n <input type="password" matInput formControlName="password">\n </mat-form-field>\n </ng-template>\n </section>\n </section>\n </mat-expansion-panel>\n</section>\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ue=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],n}return y(r,e),r.prototype.configForm=function(){return this.rabbitMqConfigForm},r.prototype.onConfigurationSet=function(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[i.Validators.required]],port:[e?e.port:null,[i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[i.Validators.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[i.Validators.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rabbit-mq-config",template:'<section [formGroup]="rabbitMqConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.exchange-name-pattern</mat-label>\n <input matInput formControlName="exchangeNamePattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.routing-key-pattern</mat-label>\n <input matInput formControlName="routingKeyPattern">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.message-properties</mat-label>\n <mat-select formControlName="messageProperties">\n <mat-option *ngFor="let property of messageProperties" [value]="property">\n {{ property }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.host</mat-label>\n <input required matInput formControlName="host">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'host\').hasError(\'required\')">\n {{ \'tb.rulenode.host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="port">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'required\')">\n {{ \'tb.rulenode.port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'min\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="rabbitMqConfigForm.get(\'port\').hasError(\'max\')">\n {{ \'tb.rulenode.port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.virtual-host</mat-label>\n <input matInput formControlName="virtualHost">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input type="password" matInput formControlName="password">\n </mat-form-field>\n <mat-checkbox formControlName="automaticRecoveryEnabled" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.connection-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="connectionTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'connectionTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.handshake-timeout-ms</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="handshakeTimeout">\n <mat-error *ngIf="rabbitMqConfigForm.get(\'handshakeTimeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.client-properties</label>\n <tb-kv-map-config\n required="false"\n formControlName="clientProperties"\n keyText="tb.rulenode.key"\n keyRequiredText="tb.rulenode.key-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),de=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.httpRequestTypes=Object.keys(Q),n}return y(r,e),r.prototype.configForm=function(){return this.restApiCallConfigForm},r.prototype.onConfigurationSet=function(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[i.Validators.required]],requestMethod:[e?e.requestMethod:null,[i.Validators.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[i.Validators.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]]})},r.prototype.validatorTriggers=function(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence"]},r.prototype.updateValidators=function(e){var t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value;t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([i.Validators.min(0)]),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([i.Validators.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-rest-api-call-config",template:'<section [formGroup]="restApiCallConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.endpoint-url-pattern</mat-label>\n <input required matInput formControlName="restEndpointUrlPattern">\n <mat-error *ngIf="restApiCallConfigForm.get(\'restEndpointUrlPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.endpoint-url-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.request-method</mat-label>\n <mat-select formControlName="requestMethod">\n <mat-option *ngFor="let requestType of httpRequestTypes" [value]="requestType">\n {{ requestType }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName="useSimpleClientHttpFactory" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n </mat-checkbox>\n <mat-form-field *ngIf="restApiCallConfigForm.get(\'useSimpleClientHttpFactory\').value === false" class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.read-timeout</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="readTimeoutMs">\n <mat-hint innerHTML="{{ \'tb.rulenode.read-timeout-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.max-parallel-requests-count</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxParallelRequestsCount">\n <mat-hint innerHTML="{{ \'tb.rulenode.max-parallel-requests-count-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <label translate class="tb-title">tb.rulenode.headers</label>\n <div class="tb-hint" translate>tb.rulenode.headers-hint</div>\n <tb-kv-map-config\n required="false"\n formControlName="headers"\n keyText="tb.rulenode.header"\n keyRequiredText="tb.rulenode.header-required"\n valText="tb.rulenode.value"\n valRequiredText="tb.rulenode.value-required">\n </tb-kv-map-config>\n <mat-checkbox formControlName="useRedisQueueForMsgPersistence" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n </mat-checkbox>\n <div fxLayout="column" *ngIf="restApiCallConfigForm.get(\'useRedisQueueForMsgPersistence\').value === true">\n <mat-checkbox formControlName="trimQueue" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.redis-queue-max-size</mat-label>\n <input type="number" step="1" min="0" matInput formControlName="maxQueueSize">\n </mat-form-field>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.smtpProtocols=["smtp","smtps"],n.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"],n}return y(r,e),r.prototype.configForm=function(){return this.sendEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})},r.prototype.validatorTriggers=function(){return["useSystemSmtpSettings"]},r.prototype.updateValidators=function(e){this.sendEmailConfigForm.get("useSystemSmtpSettings").value?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([i.Validators.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([i.Validators.required,i.Validators.min(0)])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-action-node-send-email-config",template:'<section [formGroup]="sendEmailConfigForm" fxLayout="column">\n <mat-checkbox formControlName="useSystemSmtpSettings" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n </mat-checkbox>\n <section fxLayout="column" *ngIf="sendEmailConfigForm.get(\'useSystemSmtpSettings\').value === false">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.smtp-protocol</mat-label>\n <mat-select formControlName="smtpProtocol">\n <mat-option *ngFor="let smtpProtocol of smtpProtocols" [value]="smtpProtocol">\n {{ smtpProtocol.toUpperCase() }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex="100" fxFlex.gt-sm="60" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-host</mat-label>\n <input required matInput formControlName="smtpHost">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpHost\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex="100" fxFlex.gt-sm="40" class="mat-block">\n <mat-label translate>tb.rulenode.smtp-port</mat-label>\n <input required type="number" step="1" min="1" max="65535" matInput formControlName="smtpPort">\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'required\')">\n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'min\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'smtpPort\').hasError(\'max\')">\n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.timeout-msec</mat-label>\n <input required type="number" step="1" min="0" matInput formControlName="timeout">\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'required\')">\n {{ \'tb.rulenode.timeout-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="sendEmailConfigForm.get(\'timeout\').hasError(\'min\')">\n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox formControlName="enableTls" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.enable-tls\' | translate }}\n </mat-checkbox>\n <mat-form-field class="mat-block" *ngIf="sendEmailConfigForm.get(\'enableTls\').value === true">\n <mat-label translate>tb.rulenode.tls-version</mat-label>\n <mat-select formControlName="tlsVersion">\n <mat-option *ngFor="let tlsVersion of tlsVersions" [value]="tlsVersion">\n {{ tlsVersion }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.username</mat-label>\n <input matInput placeholder="{{ \'tb.rulenode.enter-username\' | translate }}" formControlName="username">\n </mat-form-field>\n <mat-form-field class="mat-block" floatLabel="always">\n <mat-label translate>tb.rulenode.password</mat-label>\n <input matInput type="password" placeholder="{{ \'tb.rulenode.enter-password\' | translate }}" formControlName="password">\n </mat-form-field>\n </section>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ce=function(){function e(){}return e=b([t.NgModule({declarations:[T,x,q,S,I,k,N,V,E,A,L,W,J,Y,Z,ae,oe,ie,le,se,me,ue,de,pe],imports:[r.CommonModule,a.SharedModule,ne],exports:[T,x,q,S,I,k,N,V,E,A,L,W,J,Y,Z,ae,oe,ie,le,se,me,ue,de,pe]})],e)}(),fe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.checkMessageConfigForm},r.prototype.onConfigurationSet=function(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})},r.prototype.validateConfig=function(){var e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0},r.prototype.removeMessageName=function(e){var t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))},r.prototype.removeMetadataName=function(e){var t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))},r.prototype.addMessageName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("messageNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("messageNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.prototype.addMetadataName=function(e){var t=e.input,r=e.value;if((r||"").trim()){r=r.trim();var n=this.checkMessageConfigForm.get("metadataNames").value;n&&-1!==n.indexOf(r)||(n||(n=[]),n.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(n,{emitEvent:!0}))}t&&(t.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-message-config",template:'<section [formGroup]="checkMessageConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding tb-required">tb.rulenode.data-keys</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #messageNamesChipList>\n <mat-chip\n *ngFor="let messageName of checkMessageConfigForm.get(\'messageNames\').value;"\n (removed)="removeMessageName(messageName)">\n {{messageName}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.data-keys\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="messageNamesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addMessageName($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.separator-hint</div>\n <label translate class="tb-title no-padding tb-required">tb.rulenode.metadata-keys</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #metadataNamesChipList>\n <mat-chip\n *ngFor="let metadataName of checkMessageConfigForm.get(\'metadataNames\').value;"\n (removed)="removeMetadataName(metadataName)">\n {{metadataName}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.metadata-keys\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="metadataNamesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addMetadataName($event)"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <div class="tb-hint" translate>tb.rulenode.separator-hint</div>\n <mat-checkbox fxFlex formControlName="checkAllKeys" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.check-all-keys\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.check-all-keys-hint</div>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ge=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.entitySearchDirection=Object.keys(a.EntitySearchDirection),n.entitySearchDirectionTranslationsMap=a.entitySearchDirectionTranslations,n}return y(r,e),r.prototype.configForm=function(){return this.checkRelationConfigForm},r.prototype.onConfigurationSet=function(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[i.Validators.required]:[]],relationType:[e?e.relationType:null,[i.Validators.required]]})},r.prototype.validatorTriggers=function(){return["checkForSingleEntity"]},r.prototype.updateValidators=function(e){var t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[i.Validators.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-check-relation-config",template:'<section [formGroup]="checkRelationConfigForm" fxLayout="column">\n <mat-checkbox fxFlex formControlName="checkForSingleEntity" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.check-relation-hint</div>\n <mat-form-field class="mat-block" style="min-width: 100px;">\n <mat-label translate>relation.direction</mat-label>\n <mat-select formControlName="direction" required>\n <mat-option *ngFor="let direction of entitySearchDirection" [value]="direction">\n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div fxLayout="row" *ngIf="checkRelationConfigForm.get(\'checkForSingleEntity\').value" style="padding-top: 20px">\n <tb-entity-type-select\n style="min-width: 100px; padding-bottom: 20px; padding-right: 8px;"\n showLabel\n required\n formControlName="entityType">\n </tb-entity-type-select>\n <tb-entity-autocomplete\n fxFlex\n required\n *ngIf="checkRelationConfigForm.get(\'entityType\').value"\n [entityType]="checkRelationConfigForm.get(\'entityType\').value"\n formControlName="entityId">\n </tb-entity-autocomplete>\n </div>\n <tb-relation-type-autocomplete\n required\n formControlName="relationType">\n </tb-relation-type-autocomplete>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ye=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.perimeterType=M,n.perimeterTypes=Object.keys(M),n.perimeterTypeTranslationMap=w,n.rangeUnits=Object.keys(D),n.rangeUnitTranslationMap=B,n}return y(r,e),r.prototype.configForm=function(){return this.geoFilterConfigForm},r.prototype.onConfigurationSet=function(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[i.Validators.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[i.Validators.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterType:[e?e.perimeterType:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]},r.prototype.updateValidators=function(e){var t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterType").setValidators([]):this.geoFilterConfigForm.get("perimeterType").setValidators([i.Validators.required]),t||r!==M.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([i.Validators.required,i.Validators.min(-90),i.Validators.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([i.Validators.required,i.Validators.min(-180),i.Validators.max(180)]),this.geoFilterConfigForm.get("range").setValidators([i.Validators.required,i.Validators.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([i.Validators.required])),t||r!==M.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([i.Validators.required]),this.geoFilterConfigForm.get("perimeterType").updateValueAndValidity({emitEvent:!1}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-gps-geofencing-config",template:'<section [formGroup]="geoFilterConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.latitude-key-name</mat-label>\n <input matInput formControlName="latitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'latitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.longitude-key-name</mat-label>\n <input matInput formControlName="longitudeKeyName" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'longitudeKeyName\').hasError(\'required\')">\n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-checkbox fxFlex formControlName="fetchPerimeterInfoFromMessageMetadata" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n </mat-checkbox>\n <div fxLayout="row" *ngIf="!geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.perimeter-type</mat-label>\n <mat-select formControlName="perimeterType" required>\n <mat-option *ngFor="let type of perimeterTypes" [value]="type">\n {{ perimeterTypeTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column"\n *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.CIRCLE &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-latitude</mat-label>\n <input type="number" min="-90" max="90" step="0.1" matInput formControlName="centerLatitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLatitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.circle-center-longitude</mat-label>\n <input type="number" min="-180" max="180" step="0.1" matInput formControlName="centerLongitude" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'centerLongitude\').hasError(\'required\')">\n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n <div fxLayout="row" fxLayoutGap="8px">\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range</mat-label>\n <input type="number" min="0" step="0.1" matInput formControlName="range" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'range\').hasError(\'required\')">\n {{ \'tb.rulenode.range-required\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex>\n <mat-label translate>tb.rulenode.range-units</mat-label>\n <mat-select formControlName="rangeUnit" required>\n <mat-option *ngFor="let type of rangeUnits" [value]="type">\n {{ rangeUnitTranslationMap.get(type) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n <div fxLayout="row" *ngIf="geoFilterConfigForm.get(\'perimeterType\').value === perimeterType.POLYGON &&\n !geoFilterConfigForm.get(\'fetchPerimeterInfoFromMessageMetadata\').value">\n <div fxLayout="column" fxFlex="100">\n <mat-form-field class="mat-block" hintLabel="{{\'tb.rulenode.polygon-definition-hint\' | translate}}">\n <mat-label translate>tb.rulenode.polygon-definition</mat-label>\n <input matInput formControlName="polygonsDefinition" required>\n <mat-error *ngIf="geoFilterConfigForm.get(\'polygonsDefinition\').hasError(\'required\')">\n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n </mat-error>\n </mat-form-field>\n </div>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),be=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.messageTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-message-type-config",template:'<section [formGroup]="messageTypeConfigForm" fxLayout="column">\n <tb-message-types-config\n required\n label="tb.rulenode.message-types-filter"\n formControlName="messageTypes"\n ></tb-message-types-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),he=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.allowedEntityTypes=[a.EntityType.DEVICE,a.EntityType.ASSET,a.EntityType.ENTITY_VIEW,a.EntityType.TENANT,a.EntityType.CUSTOMER,a.EntityType.USER,a.EntityType.DASHBOARD,a.EntityType.RULE_CHAIN,a.EntityType.RULE_NODE],n}return y(r,e),r.prototype.configForm=function(){return this.originatorTypeConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-filter-node-originator-type-config",template:'<section [formGroup]="originatorTypeConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding tb-required">tb.rulenode.originator-types-filter</label>\n <tb-entity-type-list fxFlex\n formControlName="originatorTypes"\n [allowedEntityTypes]="allowedEntityTypes"\n [ignoreAuthorityFilter]="true"\n required>\n </tb-entity-type-list>\n</section>\n',styles:[":host ::ng-deep tb-entity-type-list .mat-form-field-flex{padding-top:0}:host ::ng-deep tb-entity-type-list .mat-form-field-infix{border-top:0}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ce=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-script-config",template:'<section [formGroup]="scriptConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.filter</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Filter"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-filter-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),ve=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.switchConfigForm},r.prototype.onConfigurationSet=function(e){this.switchConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.switchConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.switchConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-filter-node-switch-config",template:'<section [formGroup]="switchConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.switch</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Switch"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-switch-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Fe=function(e){function r(t,r,n){var o,l,s=e.call(this,t)||this;s.store=t,s.translate=r,s.fb=n,s.alarmStatusTranslationsMap=a.alarmStatusTranslations,s.alarmStatusList=[],s.searchText="",s.displayStatusFn=s.displayStatus.bind(s);try{for(var m=C(Object.keys(a.AlarmStatus)),u=m.next();!u.done;u=m.next()){var d=u.value;s.alarmStatusList.push(a.AlarmStatus[d])}}catch(e){o={error:e}}finally{try{u&&!u.done&&(l=m.return)&&l.call(m)}finally{if(o)throw o.error}}return s.statusFormControl=new i.FormControl(""),s.filteredAlarmStatus=s.statusFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return s.fetchAlarmStatus(e)})),f.share()),s}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.alarmStatusConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[i.Validators.required]]})},r.prototype.displayStatus=function(e){return e?this.translate.instant(a.alarmStatusTranslations.get(e)):void 0},r.prototype.fetchAlarmStatus=function(e){var t=this,r=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){var n=this.searchText.toUpperCase();return c.of(r.filter((function(e){return t.translate.instant(a.alarmStatusTranslations.get(a.AlarmStatus[e])).toUpperCase().includes(n)})))}return c.of(r)},r.prototype.alarmStatusSelected=function(e){this.addAlarmStatus(e.option.value),this.clear("")},r.prototype.removeAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}},r.prototype.addAlarmStatus=function(e){var t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))},r.prototype.getAlarmStatusList=function(){var e=this;return this.alarmStatusList.filter((function(t){return-1===e.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(t)}))},r.prototype.onAlarmStatusInputFocus=function(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.alarmStatusInput.nativeElement.blur(),t.alarmStatusInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("alarmStatusInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"alarmStatusInput",void 0),r=b([t.Component({selector:"tb-filter-node-check-alarm-status-config",template:'<section [formGroup]="alarmStatusConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" class="alarm-status-list">\n <mat-label translate>tb.rulenode.alarm-status-filter</mat-label>\n <mat-chip-list #alarmStatusChipList required>\n <mat-chip\n *ngFor="let alarmStatus of alarmStatusConfigForm.get(\'alarmStatusList\').value;"\n (removed)="removeAlarmStatus(alarmStatus)">\n <span>\n <strong>{{alarmStatusTranslationsMap.get(alarmStatus) | translate}}</strong>\n </span>\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text"\n style="max-width: 200px;"\n #alarmStatusInput\n (focusin)="onAlarmStatusInputFocus()"\n [formControl]="statusFormControl"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="alarmStatusAutocomplete"\n [matChipInputFor]="alarmStatusChipList">\n </mat-chip-list>\n <mat-autocomplete #alarmStatusAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="alarmStatusSelected($event)"\n [displayWith]="displayStatusFn">\n <mat-option *ngFor="let status of filteredAlarmStatus | async" [value]="status">\n <span [innerHTML]="alarmStatusTranslationsMap.get(status) | translate | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredAlarmStatus | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div>\n <span translate>tb.rulenode.no-alarm-status-matching</span>\n </div>\n </div>\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n <tb-error [error]="(statusFormControl.touched &&\n alarmStatusConfigForm.get(\'alarmStatusList\').hasError(\'required\'))\n ? translate.instant(\'tb.rulenode.alarm-status-list-empty\') : \'\'"></tb-error>\n </section>\n\n\n\n'}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Te=function(){function e(){}return e=b([t.NgModule({declarations:[fe,ge,ye,be,he,Ce,ve,Fe],imports:[r.CommonModule,a.SharedModule,ne],exports:[fe,ge,ye,be,he,Ce,ve,Fe]})],e)}(),xe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.customerAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-customer-attributes-config",template:'<section [formGroup]="customerAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.attr-mapping</label>\n <mat-checkbox fxFlex formControlName="telemetry" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n </mat-checkbox>\n <tb-kv-map-config\n required\n formControlName="attrMapping"\n requiredText="tb.rulenode.attr-mapping-required"\n keyText="{{ customerAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry\' : \'tb.rulenode.source-attribute\' }}"\n keyRequiredText="{{ customerAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry-required\' : \'tb.rulenode.source-attribute-required\' }}"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),qe=function(e){function r(t,r,n){var a,o,l=e.call(this,t)||this;l.store=t,l.translate=r,l.fb=n,l.entityDetailsTranslationsMap=H,l.entityDetailsList=[],l.searchText="",l.displayDetailsFn=l.displayDetails.bind(l);try{for(var s=C(Object.keys(K)),m=s.next();!m.done;m=s.next()){var u=m.value;l.entityDetailsList.push(K[u])}}catch(e){a={error:e}}finally{try{m&&!m.done&&(o=s.return)&&o.call(s)}finally{if(a)throw a.error}}return l.detailsFormControl=new i.FormControl(""),l.filteredEntityDetails=l.detailsFormControl.valueChanges.pipe(f.startWith(""),f.map((function(e){return e||""})),f.mergeMap((function(e){return l.fetchEntityDetails(e)})),f.share()),l}return y(r,e),r.prototype.ngOnInit=function(){e.prototype.ngOnInit.call(this)},r.prototype.configForm=function(){return this.entityDetailsConfigForm},r.prototype.prepareInputConfig=function(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),e},r.prototype.onConfigurationSet=function(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[i.Validators.required]],addToMetadata:[!!e&&e.addToMetadata,[]]})},r.prototype.displayDetails=function(e){return e?this.translate.instant(H.get(e)):void 0},r.prototype.fetchEntityDetails=function(e){var t=this;if(this.searchText=e,this.searchText&&this.searchText.length){var r=this.searchText.toUpperCase();return c.of(this.entityDetailsList.filter((function(e){return t.translate.instant(H.get(K[e])).toUpperCase().includes(r)})))}return c.of(this.entityDetailsList)},r.prototype.detailsFieldSelected=function(e){this.addDetailsField(e.option.value),this.clear("")},r.prototype.removeDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;if(t){var r=t.indexOf(e);r>=0&&(t.splice(r,1),this.entityDetailsConfigForm.get("detailsList").setValue(t))}},r.prototype.addDetailsField=function(e){var t=this.entityDetailsConfigForm.get("detailsList").value;t||(t=[]),-1===t.indexOf(e)&&(t.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(t))},r.prototype.onEntityDetailsInputFocus=function(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})},r.prototype.clear=function(e){var t=this;void 0===e&&(e=""),this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((function(){t.detailsInput.nativeElement.blur(),t.detailsInput.nativeElement.focus()}),0)},r.ctorParameters=function(){return[{type:o.Store},{type:n.TranslateService},{type:i.FormBuilder}]},b([t.ViewChild("detailsInput",{static:!1}),h("design:type",t.ElementRef)],r.prototype,"detailsInput",void 0),r=b([t.Component({selector:"tb-enrichment-node-entity-details-config",template:'<section [formGroup]="entityDetailsConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" class="entity-fields-list">\n <mat-label translate>tb.rulenode.entity-details</mat-label>\n <mat-chip-list #detailsChipList required>\n <mat-chip\n *ngFor="let details of entityDetailsConfigForm.get(\'detailsList\').value;"\n (removed)="removeDetailsField(details)">\n <span>\n <strong>{{entityDetailsTranslationsMap.get(details) | translate}}</strong>\n </span>\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text"\n style="max-width: 200px;"\n #detailsInput\n (focusin)="onEntityDetailsInputFocus()"\n [formControl]="detailsFormControl"\n matAutocompleteOrigin\n #origin="matAutocompleteOrigin"\n [matAutocompleteConnectedTo]="origin"\n [matAutocomplete]="detailsAutocomplete"\n [matChipInputFor]="detailsChipList">\n </mat-chip-list>\n <mat-autocomplete #detailsAutocomplete="matAutocomplete"\n class="tb-autocomplete"\n (optionSelected)="detailsFieldSelected($event)"\n [displayWith]="displayDetailsFn">\n <mat-option *ngFor="let details of filteredEntityDetails | async" [value]="details">\n <span [innerHTML]="entityDetailsTranslationsMap.get(details) | translate | highlight:searchText"></span>\n </mat-option>\n <mat-option *ngIf="(filteredEntityDetails | async)?.length === 0" [value]="null" class="tb-not-found">\n <div class="tb-not-found-content" (click)="$event.stopPropagation()">\n <div>\n <span translate>tb.rulenode.no-entity-details-matching</span>\n </div>\n </div>\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n <tb-error [error]="(detailsFormControl.touched &&\n entityDetailsConfigForm.get(\'detailsList\').hasError(\'required\'))\n ? translate.instant(\'tb.rulenode.entity-details-list-empty\') : \'\'"></tb-error>\n <mat-checkbox fxFlex formControlName="addToMetadata" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.add-to-metadata-hint</div>\n</section>\n',styles:[":host ::ng-deep mat-form-field.entity-fields-list .mat-form-field-wrapper{margin-bottom:-1.25em}"]}),h("design:paramtypes",[o.Store,n.TranslateService,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Se=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.deviceAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[i.Validators.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.deviceAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.deviceAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-device-attributes-config",template:'<section [formGroup]="deviceAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.device-relations-query</label>\n <tb-device-relations-query-config\n required\n formControlName="deviceRelationsQuery"\n style="padding-bottom: 15px;">\n </tb-device-relations-query-config>\n <mat-checkbox fxFlex formControlName="tellFailureIfAbsent" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.tell-failure-if-absent-hint</div>\n <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #clientAttributesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'clientAttributeNames\').value;"\n (removed)="removeKey(key, \'clientAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.client-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="clientAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'clientAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #sharedAttributesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'sharedAttributeNames\').value;"\n (removed)="removeKey(key, \'sharedAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="sharedAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'sharedAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #serverAttributesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'serverAttributeNames\').value;"\n (removed)="removeKey(key, \'serverAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.server-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="serverAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'serverAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #latestTimeseriesChipList>\n <mat-chip\n *ngFor="let key of deviceAttributesConfigForm.get(\'latestTsKeyNames\').value;"\n (removed)="removeKey(key, \'latestTsKeyNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="latestTimeseriesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'latestTsKeyNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <mat-checkbox formControlName="getLatestValueWithTs" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" innerHTML="{{ \'tb.rulenode.get-latest-value-with-ts-hint\' | translate }}"></div>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ie=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n}return y(r,e),r.prototype.configForm=function(){return this.originatorAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})},r.prototype.removeKey=function(e,t){var r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.originatorAttributesConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.originatorAttributesConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-attributes-config",template:'<section [formGroup]="originatorAttributesConfigForm" fxLayout="column">\n <mat-checkbox fxFlex formControlName="tellFailureIfAbsent" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" translate>tb.rulenode.tell-failure-if-absent-hint</div>\n <label translate class="tb-title no-padding">tb.rulenode.client-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #clientAttributesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'clientAttributeNames\').value;"\n (removed)="removeKey(key, \'clientAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.client-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="clientAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'clientAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.shared-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #sharedAttributesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'sharedAttributeNames\').value;"\n (removed)="removeKey(key, \'sharedAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.shared-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="sharedAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'sharedAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.server-attributes</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #serverAttributesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'serverAttributeNames\').value;"\n (removed)="removeKey(key, \'serverAttributeNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.server-attributes\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="serverAttributesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'serverAttributeNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #latestTimeseriesChipList>\n <mat-chip\n *ngFor="let key of originatorAttributesConfigForm.get(\'latestTsKeyNames\').value;"\n (removed)="removeKey(key, \'latestTsKeyNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="latestTimeseriesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'latestTsKeyNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <mat-checkbox formControlName="getLatestValueWithTs" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" innerHTML="{{ \'tb.rulenode.get-latest-value-with-ts-hint\' | translate }}"></div>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),ke=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.originatorFieldsConfigForm},r.prototype.onConfigurationSet=function(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-originator-fields-config",template:'<section [formGroup]="originatorFieldsConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.fields-mapping</label>\n <tb-kv-map-config\n required\n formControlName="fieldsMapping"\n requiredText="tb.rulenode.fields-mapping-required"\n keyText="tb.rulenode.source-field"\n keyRequiredText="tb.rulenode.source-field-required"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ne=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.separatorKeysCodes=[s.ENTER,s.COMMA,s.SEMICOLON],n.fetchMode=j,n.fetchModes=Object.keys(j),n.samplingOrders=Object.keys(U),n.timeUnits=Object.keys(R),n.timeUnitsTranslationMap=O,n}return y(r,e),r.prototype.configForm=function(){return this.getTelemetryFromDatabaseConfigForm},r.prototype.onConfigurationSet=function(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],fetchMode:[e?e.fetchMode:null,[i.Validators.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})},r.prototype.validatorTriggers=function(){return["fetchMode","useMetadataIntervalPatterns"]},r.prototype.updateValidators=function(e){var t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===j.ALL?(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([i.Validators.required,i.Validators.min(2),i.Validators.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([i.Validators.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([i.Validators.required,i.Validators.min(1),i.Validators.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([i.Validators.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})},r.prototype.removeKey=function(e,t){var r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))},r.prototype.addKey=function(e,t){var r=e.input,n=e.value;if((n||"").trim()){n=n.trim();var a=this.getTelemetryFromDatabaseConfigForm.get(t).value;a&&-1!==a.indexOf(n)||(a||(a=[]),a.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(a,{emitEvent:!0}))}r&&(r.value="")},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-get-telemetry-from-database",template:'<section [formGroup]="getTelemetryFromDatabaseConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.latest-timeseries</label>\n <mat-form-field floatLabel="always" class="mat-block">\n <mat-label></mat-label>\n <mat-chip-list #latestTimeseriesChipList>\n <mat-chip\n *ngFor="let key of getTelemetryFromDatabaseConfigForm.get(\'latestTsKeyNames\').value;"\n (removed)="removeKey(key, \'latestTsKeyNames\')">\n {{key}}\n <mat-icon matChipRemove>close</mat-icon>\n </mat-chip>\n <input matInput type="text" placeholder="{{\'tb.rulenode.latest-timeseries\' | translate}}"\n style="max-width: 200px;"\n [matChipInputFor]="latestTimeseriesChipList"\n [matChipInputSeparatorKeyCodes]="separatorKeysCodes"\n (matChipInputTokenEnd)="addKey($event, \'latestTsKeyNames\')"\n [matChipInputAddOnBlur]="true">\n </mat-chip-list>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.fetch-mode</mat-label>\n <mat-select formControlName="fetchMode" required>\n <mat-option *ngFor="let mode of fetchModes" [value]="mode">\n {{ mode }}\n </mat-option>\n </mat-select>\n <mat-hint translate>tb.rulenode.fetch-mode-hint</mat-hint>\n </mat-form-field>\n <div fxLayout="column" *ngIf="getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value === fetchMode.ALL">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.order-by</mat-label>\n <mat-select formControlName="orderBy" required>\n <mat-option *ngFor="let order of samplingOrders" [value]="order">\n {{ order }}\n </mat-option>\n </mat-select>\n <mat-hint translate>tb.rulenode.order-by-hint</mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.limit</mat-label>\n <input type="number" min="2" max="1000" step="1" matInput formControlName="limit" required>\n <mat-hint translate>tb.rulenode.limit-hint</mat-hint>\n </mat-form-field>\n </div>\n <mat-checkbox formControlName="useMetadataIntervalPatterns">\n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n </mat-checkbox>\n <div class="tb-hint" style="padding-bottom: 16px;" translate>tb.rulenode.use-metadata-interval-patterns-hint</div>\n <div fxLayout="column" *ngIf="getTelemetryFromDatabaseConfigForm.get(\'useMetadataIntervalPatterns\').value === false; else intervalPattern">\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.start-interval</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="startInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.start-interval-time-unit</mat-label>\n <mat-select formControlName="startIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div fxLayout="column" fxLayout.gt-sm="row" fxLayoutGap.gt-sm="8px">\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.end-interval</mat-label>\n <input type="number" step="1" min="1" max="2147483647" matInput formControlName="endInterval" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endInterval\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endInterval\').hasError(\'min\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endInterval\').hasError(\'max\')">\n {{ \'tb.rulenode.time-value-range\' | translate }}\n </mat-error>\n </mat-form-field>\n <mat-form-field fxFlex class="mat-block">\n <mat-label translate>tb.rulenode.end-interval-time-unit</mat-label>\n <mat-select formControlName="endIntervalTimeUnit" required>\n <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">\n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n <ng-template #intervalPattern>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.start-interval-pattern</mat-label>\n <input matInput formControlName="startIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'startIntervalPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.start-interval-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.end-interval-pattern</mat-label>\n <input matInput formControlName="endIntervalPattern" required>\n <mat-error *ngIf="getTelemetryFromDatabaseConfigForm.get(\'endIntervalPattern\').hasError(\'required\')">\n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.end-interval-pattern-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n </ng-template>\n</section>\n',styles:[":host label.tb-title{margin-bottom:-10px}"]}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ve=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.relatedAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[i.Validators.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-related-attributes-config",template:'<section [formGroup]="relatedAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.relations-query</label>\n <tb-relations-query-config\n required\n formControlName="relationsQuery"\n style="padding-bottom: 15px;">\n </tb-relations-query-config>\n <label translate class="tb-title tb-required">tb.rulenode.attr-mapping</label>\n <mat-checkbox fxFlex formControlName="telemetry" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n </mat-checkbox>\n <tb-kv-map-config\n required\n formControlName="attrMapping"\n requiredText="tb.rulenode.attr-mapping-required"\n keyText="{{ relatedAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry\' : \'tb.rulenode.source-attribute\' }}"\n keyRequiredText="{{ relatedAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry-required\' : \'tb.rulenode.source-attribute-required\' }}"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ee=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.tenantAttributesConfigForm},r.prototype.onConfigurationSet=function(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-enrichment-node-tenant-attributes-config",template:'<section [formGroup]="tenantAttributesConfigForm" fxLayout="column">\n <label translate class="tb-title tb-required">tb.rulenode.attr-mapping</label>\n <mat-checkbox fxFlex formControlName="telemetry" style="padding-bottom: 16px;">\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n </mat-checkbox>\n <tb-kv-map-config\n required\n formControlName="attrMapping"\n requiredText="tb.rulenode.attr-mapping-required"\n keyText="{{ tenantAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry\' : \'tb.rulenode.source-attribute\' }}"\n keyRequiredText="{{ tenantAttributesConfigForm.get(\'telemetry\').value ? \'tb.rulenode.source-telemetry-required\' : \'tb.rulenode.source-attribute-required\' }}"\n valText="tb.rulenode.target-attribute"\n valRequiredText="tb.rulenode.target-attribute-required">\n </tb-kv-map-config>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Ae=function(){function e(){}return e=b([t.NgModule({declarations:[xe,qe,Se,Ie,ke,Ne,Ve,Ee],imports:[r.CommonModule,a.SharedModule,ne],exports:[xe,qe,Se,Ie,ke,Ne,Ve,Ee]})],e)}(),Le=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n.originatorSource=v,n.originatorSources=Object.keys(v),n.originatorSourceTranslationMap=P,n}return y(r,e),r.prototype.configForm=function(){return this.changeOriginatorConfigForm},r.prototype.onConfigurationSet=function(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[i.Validators.required]],relationsQuery:[e?e.relationsQuery:null,[]]})},r.prototype.validatorTriggers=function(){return["originatorSource"]},r.prototype.updateValidators=function(e){var t=this.changeOriginatorConfigForm.get("originatorSource").value;t&&t===v.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([i.Validators.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-change-originator-config",template:'<section [formGroup]="changeOriginatorConfigForm" fxLayout="column">\n <mat-form-field class="mat-block">\n <mat-label translate>tb.rulenode.originator-source</mat-label>\n <mat-select formControlName="originatorSource" required>\n <mat-option *ngFor="let source of originatorSources" [value]="source">\n {{ originatorSourceTranslationMap.get(source) | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <section fxLayout="column" *ngIf="changeOriginatorConfigForm.get(\'originatorSource\').value === originatorSource.RELATED">\n <label translate class="tb-title tb-required">tb.rulenode.relations-query</label>\n <tb-relations-query-config\n required\n formControlName="relationsQuery"\n style="padding-bottom: 15px;">\n </tb-relations-query-config>\n </section>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Me=function(e){function r(t,r,n,a){var o=e.call(this,t)||this;return o.store=t,o.fb=r,o.nodeScriptTestService=n,o.translate=a,o}return y(r,e),r.prototype.configForm=function(){return this.scriptConfigForm},r.prototype.onConfigurationSet=function(e){this.scriptConfigForm=this.fb.group({jsScript:[e?e.jsScript:null,[i.Validators.required]]})},r.prototype.testScript=function(){var e=this,t=this.scriptConfigForm.get("jsScript").value;this.nodeScriptTestService.testNodeScript(t,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId).subscribe((function(t){t&&e.scriptConfigForm.get("jsScript").setValue(t)}))},r.prototype.onValidate=function(){this.jsFuncComponent.validateOnSubmit()},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder},{type:l.NodeScriptTestService},{type:n.TranslateService}]},b([t.ViewChild("jsFuncComponent",{static:!0}),h("design:type",a.JsFuncComponent)],r.prototype,"jsFuncComponent",void 0),r=b([t.Component({selector:"tb-transformation-node-script-config",template:'<section [formGroup]="scriptConfigForm" fxLayout="column">\n <label translate class="tb-title no-padding">tb.rulenode.transform</label>\n <tb-js-func #jsFuncComponent\n formControlName="jsScript"\n functionName="Transform"\n [functionArgs]="[\'msg\', \'metadata\', \'msgType\']"\n noValidate="true">\n </tb-js-func>\n <div fxLayout="row">\n <button mat-button mat-raised-button color="primary" (click)="testScript()">\n {{ \'tb.rulenode.test-transformer-function\' | translate }}\n </button>\n </div>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder,l.NodeScriptTestService,n.TranslateService])],r)}(a.RuleNodeConfigurationComponent),Pe=function(e){function r(t,r){var n=e.call(this,t)||this;return n.store=t,n.fb=r,n}return y(r,e),r.prototype.configForm=function(){return this.toEmailConfigForm},r.prototype.onConfigurationSet=function(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[i.Validators.required]],toTemplate:[e?e.toTemplate:null,[i.Validators.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[i.Validators.required]],bodyTemplate:[e?e.bodyTemplate:null,[i.Validators.required]]})},r.ctorParameters=function(){return[{type:o.Store},{type:i.FormBuilder}]},r=b([t.Component({selector:"tb-transformation-node-to-email-config",template:'<section [formGroup]="toEmailConfigForm" fxLayout="column">\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.from-template</mat-label>\n <textarea required matInput formControlName="fromTemplate" rows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'fromTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.from-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.from-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.to-template</mat-label>\n <textarea required matInput formControlName="toTemplate" rows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'toTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.to-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.mail-address-list-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.cc-template</mat-label>\n <textarea matInput formControlName="ccTemplate" rows="2"></textarea>\n <mat-hint innerHTML="{{ \'tb.rulenode.mail-address-list-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.bcc-template</mat-label>\n <textarea matInput formControlName="bccTemplate" rows="2"></textarea>\n <mat-hint innerHTML="{{ \'tb.rulenode.mail-address-list-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.subject-template</mat-label>\n <textarea required matInput formControlName="subjectTemplate" rows="2"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'subjectTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.subject-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.subject-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n <mat-form-field class="mat-block" style="padding-bottom: 16px;">\n <mat-label translate>tb.rulenode.body-template</mat-label>\n <textarea required matInput formControlName="bodyTemplate" rows="6"></textarea>\n <mat-error *ngIf="toEmailConfigForm.get(\'bodyTemplate\').hasError(\'required\')">\n {{ \'tb.rulenode.body-template-required\' | translate }}\n </mat-error>\n <mat-hint innerHTML="{{ \'tb.rulenode.body-template-hint\' | translate }}"></mat-hint>\n </mat-form-field>\n</section>\n'}),h("design:paramtypes",[o.Store,i.FormBuilder])],r)}(a.RuleNodeConfigurationComponent),Re=function(){function e(){}return e=b([t.NgModule({declarations:[Le,Me,Pe],imports:[r.CommonModule,a.SharedModule,ne],exports:[Le,Me,Pe]})],e)}(),we=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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","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 <code>${metaKeyName}</code> to substitute variables from metadata","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","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 <code>${metaKeyName}</code> 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","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> to substitute variables from metadata","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":"Use <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> 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 <code>${metaKeyName}</code> to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use <code>${metaKeyName}</code> 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","tls-version":"TLS version","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".',"get-latest-value-with-ts":"Fetch Latest telemetry with Timestamp","get-latest-value-with-ts-hint":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "temp": "&lcub;\\"ts\\":1574329385897,\\"value\\":42&rcub;"',"use-redis-queue":"Use redis queue for message persistence","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}},!0)}(e)}return e.ctorParameters=function(){return[{type:n.TranslateService}]},e=b([t.NgModule({declarations:[F],imports:[r.CommonModule,a.SharedModule],exports:[ce,Te,Ae,Re,F]}),h("design:paramtypes",[n.TranslateService])],e)}();e.RuleNodeCoreConfigModule=we,e.ɵa=F,e.ɵb=ce,e.ɵba=ne,e.ɵbb=X,e.ɵbc=ee,e.ɵbd=te,e.ɵbe=re,e.ɵbf=Te,e.ɵbg=fe,e.ɵbh=ge,e.ɵbi=ye,e.ɵbj=be,e.ɵbk=he,e.ɵbl=Ce,e.ɵbm=ve,e.ɵbn=Fe,e.ɵbo=Ae,e.ɵbp=xe,e.ɵbq=qe,e.ɵbr=Se,e.ɵbs=Ie,e.ɵbt=ke,e.ɵbu=Ne,e.ɵbv=Ve,e.ɵbw=Ee,e.ɵbx=Re,e.ɵby=Le,e.ɵbz=Me,e.ɵc=T,e.ɵca=Pe,e.ɵd=x,e.ɵe=q,e.ɵf=S,e.ɵg=I,e.ɵh=k,e.ɵi=N,e.ɵj=V,e.ɵk=E,e.ɵl=A,e.ɵm=L,e.ɵn=W,e.ɵo=J,e.ɵp=Y,e.ɵq=Z,e.ɵr=ae,e.ɵs=oe,e.ɵt=ie,e.ɵu=le,e.ɵv=se,e.ɵw=me,e.ɵx=ue,e.ɵy=de,e.ɵz=pe,Object.defineProperty(e,"__esModule",{value:!0})}));
16 -//# sourceMappingURL=rulenode-core-config.umd.min.js.map  
  16 +//# sourceMappingURL=rulenode-core-config.umd.min.js.map
  1 + Apache License
  2 + Version 2.0, January 2004
  3 + http://www.apache.org/licenses/
  4 +
  5 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
  6 +
  7 + 1. Definitions.
  8 +
  9 + "License" shall mean the terms and conditions for use, reproduction,
  10 + and distribution as defined by Sections 1 through 9 of this document.
  11 +
  12 + "Licensor" shall mean the copyright owner or entity authorized by
  13 + the copyright owner that is granting the License.
  14 +
  15 + "Legal Entity" shall mean the union of the acting entity and all
  16 + other entities that control, are controlled by, or are under common
  17 + control with that entity. For the purposes of this definition,
  18 + "control" means (i) the power, direct or indirect, to cause the
  19 + direction or management of such entity, whether by contract or
  20 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
  21 + outstanding shares, or (iii) beneficial ownership of such entity.
  22 +
  23 + "You" (or "Your") shall mean an individual or Legal Entity
  24 + exercising permissions granted by this License.
  25 +
  26 + "Source" form shall mean the preferred form for making modifications,
  27 + including but not limited to software source code, documentation
  28 + source, and configuration files.
  29 +
  30 + "Object" form shall mean any form resulting from mechanical
  31 + transformation or translation of a Source form, including but
  32 + not limited to compiled object code, generated documentation,
  33 + and conversions to other media types.
  34 +
  35 + "Work" shall mean the work of authorship, whether in Source or
  36 + Object form, made available under the License, as indicated by a
  37 + copyright notice that is included in or attached to the work
  38 + (an example is provided in the Appendix below).
  39 +
  40 + "Derivative Works" shall mean any work, whether in Source or Object
  41 + form, that is based on (or derived from) the Work and for which the
  42 + editorial revisions, annotations, elaborations, or other modifications
  43 + represent, as a whole, an original work of authorship. For the purposes
  44 + of this License, Derivative Works shall not include works that remain
  45 + separable from, or merely link (or bind by name) to the interfaces of,
  46 + the Work and Derivative Works thereof.
  47 +
  48 + "Contribution" shall mean any work of authorship, including
  49 + the original version of the Work and any modifications or additions
  50 + to that Work or Derivative Works thereof, that is intentionally
  51 + submitted to Licensor for inclusion in the Work by the copyright owner
  52 + or by an individual or Legal Entity authorized to submit on behalf of
  53 + the copyright owner. For the purposes of this definition, "submitted"
  54 + means any form of electronic, verbal, or written communication sent
  55 + to the Licensor or its representatives, including but not limited to
  56 + communication on electronic mailing lists, source code control systems,
  57 + and issue tracking systems that are managed by, or on behalf of, the
  58 + Licensor for the purpose of discussing and improving the Work, but
  59 + excluding communication that is conspicuously marked or otherwise
  60 + designated in writing by the copyright owner as "Not a Contribution."
  61 +
  62 + "Contributor" shall mean Licensor and any individual or Legal Entity
  63 + on behalf of whom a Contribution has been received by Licensor and
  64 + subsequently incorporated within the Work.
  65 +
  66 + 2. Grant of Copyright License. Subject to the terms and conditions of
  67 + this License, each Contributor hereby grants to You a perpetual,
  68 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  69 + copyright license to reproduce, prepare Derivative Works of,
  70 + publicly display, publicly perform, sublicense, and distribute the
  71 + Work and such Derivative Works in Source or Object form.
  72 +
  73 + 3. Grant of Patent License. Subject to the terms and conditions of
  74 + this License, each Contributor hereby grants to You a perpetual,
  75 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
  76 + (except as stated in this section) patent license to make, have made,
  77 + use, offer to sell, sell, import, and otherwise transfer the Work,
  78 + where such license applies only to those patent claims licensable
  79 + by such Contributor that are necessarily infringed by their
  80 + Contribution(s) alone or by combination of their Contribution(s)
  81 + with the Work to which such Contribution(s) was submitted. If You
  82 + institute patent litigation against any entity (including a
  83 + cross-claim or counterclaim in a lawsuit) alleging that the Work
  84 + or a Contribution incorporated within the Work constitutes direct
  85 + or contributory patent infringement, then any patent licenses
  86 + granted to You under this License for that Work shall terminate
  87 + as of the date such litigation is filed.
  88 +
  89 + 4. Redistribution. You may reproduce and distribute copies of the
  90 + Work or Derivative Works thereof in any medium, with or without
  91 + modifications, and in Source or Object form, provided that You
  92 + meet the following conditions:
  93 +
  94 + (a) You must give any other recipients of the Work or
  95 + Derivative Works a copy of this License; and
  96 +
  97 + (b) You must cause any modified files to carry prominent notices
  98 + stating that You changed the files; and
  99 +
  100 + (c) You must retain, in the Source form of any Derivative Works
  101 + that You distribute, all copyright, patent, trademark, and
  102 + attribution notices from the Source form of the Work,
  103 + excluding those notices that do not pertain to any part of
  104 + the Derivative Works; and
  105 +
  106 + (d) If the Work includes a "NOTICE" text file as part of its
  107 + distribution, then any Derivative Works that You distribute must
  108 + include a readable copy of the attribution notices contained
  109 + within such NOTICE file, excluding those notices that do not
  110 + pertain to any part of the Derivative Works, in at least one
  111 + of the following places: within a NOTICE text file distributed
  112 + as part of the Derivative Works; within the Source form or
  113 + documentation, if provided along with the Derivative Works; or,
  114 + within a display generated by the Derivative Works, if and
  115 + wherever such third-party notices normally appear. The contents
  116 + of the NOTICE file are for informational purposes only and
  117 + do not modify the License. You may add Your own attribution
  118 + notices within Derivative Works that You distribute, alongside
  119 + or as an addendum to the NOTICE text from the Work, provided
  120 + that such additional attribution notices cannot be construed
  121 + as modifying the License.
  122 +
  123 + You may add Your own copyright statement to Your modifications and
  124 + may provide additional or different license terms and conditions
  125 + for use, reproduction, or distribution of Your modifications, or
  126 + for any such Derivative Works as a whole, provided Your use,
  127 + reproduction, and distribution of the Work otherwise complies with
  128 + the conditions stated in this License.
  129 +
  130 + 5. Submission of Contributions. Unless You explicitly state otherwise,
  131 + any Contribution intentionally submitted for inclusion in the Work
  132 + by You to the Licensor shall be under the terms and conditions of
  133 + this License, without any additional terms or conditions.
  134 + Notwithstanding the above, nothing herein shall supersede or modify
  135 + the terms of any separate license agreement you may have executed
  136 + with Licensor regarding such Contributions.
  137 +
  138 + 6. Trademarks. This License does not grant permission to use the trade
  139 + names, trademarks, service marks, or product names of the Licensor,
  140 + except as required for reasonable and customary use in describing the
  141 + origin of the Work and reproducing the content of the NOTICE file.
  142 +
  143 + 7. Disclaimer of Warranty. Unless required by applicable law or
  144 + agreed to in writing, Licensor provides the Work (and each
  145 + Contributor provides its Contributions) on an "AS IS" BASIS,
  146 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  147 + implied, including, without limitation, any warranties or conditions
  148 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
  149 + PARTICULAR PURPOSE. You are solely responsible for determining the
  150 + appropriateness of using or redistributing the Work and assume any
  151 + risks associated with Your exercise of permissions under this License.
  152 +
  153 + 8. Limitation of Liability. In no event and under no legal theory,
  154 + whether in tort (including negligence), contract, or otherwise,
  155 + unless required by applicable law (such as deliberate and grossly
  156 + negligent acts) or agreed to in writing, shall any Contributor be
  157 + liable to You for damages, including any direct, indirect, special,
  158 + incidental, or consequential damages of any character arising as a
  159 + result of this License or out of the use or inability to use the
  160 + Work (including but not limited to damages for loss of goodwill,
  161 + work stoppage, computer failure or malfunction, or any and all
  162 + other commercial damages or losses), even if such Contributor
  163 + has been advised of the possibility of such damages.
  164 +
  165 + 9. Accepting Warranty or Additional Liability. While redistributing
  166 + the Work or Derivative Works thereof, You may choose to offer,
  167 + and charge a fee for, acceptance of support, warranty, indemnity,
  168 + or other liability obligations and/or rights consistent with this
  169 + License. However, in accepting such obligations, You may act only
  170 + on Your own behalf and on Your sole responsibility, not on behalf
  171 + of any other Contributor, and only if You agree to indemnify,
  172 + defend, and hold each Contributor harmless for any liability
  173 + incurred by, or claims asserted against, such Contributor by reason
  174 + of your accepting any such warranty or additional liability.
  175 +
  176 + END OF TERMS AND CONDITIONS
  177 +
  178 + APPENDIX: How to apply the Apache License to your work.
  179 +
  180 + To apply the Apache License to your work, attach the following
  181 + boilerplate notice, with the fields enclosed by brackets "[]"
  182 + replaced with your own identifying information. (Don't include
  183 + the brackets!) The text should be enclosed in the appropriate
  184 + comment syntax for the file format. We also recommend that a
  185 + file or class name and description of purpose be included on the
  186 + same "printed page" as the copyright notice for easier
  187 + identification within third-party archives.
  188 +
  189 + Copyright [yyyy] [name of copyright owner]
  190 +
  191 + Licensed under the Apache License, Version 2.0 (the "License");
  192 + you may not use this file except in compliance with the License.
  193 + You may obtain a copy of the License at
  194 +
  195 + http://www.apache.org/licenses/LICENSE-2.0
  196 +
  197 + Unless required by applicable law or agreed to in writing, software
  198 + distributed under the License is distributed on an "AS IS" BASIS,
  199 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  200 + See the License for the specific language governing permissions and
  201 + limitations under the License.
@@ -37,7 +37,9 @@ @@ -37,7 +37,9 @@
37 "node_modules/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css", 37 "node_modules/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css",
38 "src/app/shared/components/json-form/react/json-form.scss", 38 "src/app/shared/components/json-form/react/json-form.scss",
39 "node_modules/rc-select/assets/index.less", 39 "node_modules/rc-select/assets/index.less",
40 - "node_modules/jstree-bootstrap-theme/dist/themes/proton/style.min.css" 40 + "node_modules/jstree-bootstrap-theme/dist/themes/proton/style.min.css",
  41 + "node_modules/leaflet/dist/leaflet.css",
  42 + "src/app/modules/home/components/widget/lib/maps/markers.scss"
41 ], 43 ],
42 "stylePreprocessorOptions": { 44 "stylePreprocessorOptions": {
43 "includePaths": [ 45 "includePaths": [
@@ -1833,6 +1833,12 @@ @@ -1833,6 +1833,12 @@
1833 "resolved": "https://registry.npmjs.org/@types/flowjs/-/flowjs-2.13.1.tgz", 1833 "resolved": "https://registry.npmjs.org/@types/flowjs/-/flowjs-2.13.1.tgz",
1834 "integrity": "sha512-cPuORQrWmJV7pmiSt1ApDOsQSooVka53Ugr3LB0MW/bsG/fDtOXSxsT5Aiej98VD3eCIZNyABfk3NBWU7CorsQ==" 1834 "integrity": "sha512-cPuORQrWmJV7pmiSt1ApDOsQSooVka53Ugr3LB0MW/bsG/fDtOXSxsT5Aiej98VD3eCIZNyABfk3NBWU7CorsQ=="
1835 }, 1835 },
  1836 + "@types/geojson": {
  1837 + "version": "7946.0.7",
  1838 + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
  1839 + "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==",
  1840 + "dev": true
  1841 + },
1836 "@types/glob": { 1842 "@types/glob": {
1837 "version": "7.1.1", 1843 "version": "7.1.1",
1838 "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", 1844 "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
@@ -1882,6 +1888,30 @@ @@ -1882,6 +1888,30 @@
1882 "@types/jquery": "*" 1888 "@types/jquery": "*"
1883 } 1889 }
1884 }, 1890 },
  1891 + "@types/leaflet": {
  1892 + "version": "1.5.9",
  1893 + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.5.9.tgz",
  1894 + "integrity": "sha512-vFj2Y764lC6PpmmoFTui3yEMAKf+Dy08eGIaFgM+efJoKNxDP/bsEr2UHloP6kkJqc+4VO9+KYea2ZhiZCnNrQ==",
  1895 + "dev": true,
  1896 + "requires": {
  1897 + "@types/geojson": "*"
  1898 + }
  1899 + },
  1900 + "@types/leaflet-polylinedecorator": {
  1901 + "version": "1.6.0",
  1902 + "resolved": "https://registry.npmjs.org/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz",
  1903 + "integrity": "sha512-Z2BXZDjKEqHclwrAmhYdF1RwyFfa/NFxsoF79sitzaj5D/4YWHp/zDRcUZar5cQFKRgK66AYEIF7nKVuMzUGdw==",
  1904 + "dev": true,
  1905 + "requires": {
  1906 + "@types/leaflet": "*"
  1907 + }
  1908 + },
  1909 + "@types/lodash": {
  1910 + "version": "4.14.149",
  1911 + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
  1912 + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==",
  1913 + "dev": true
  1914 + },
1885 "@types/minimatch": { 1915 "@types/minimatch": {
1886 "version": "3.0.3", 1916 "version": "3.0.3",
1887 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 1917 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@@ -1894,9 +1924,9 @@ @@ -1894,9 +1924,9 @@
1894 "integrity": "sha512-13gmo3M2qVvjQrWNseqM3+cR6S2Ss3grbR2NZltgMq94wOwqJYQdgn8qzwDshzgXqMlSUtyPZjysImmktu22ew==" 1924 "integrity": "sha512-13gmo3M2qVvjQrWNseqM3+cR6S2Ss3grbR2NZltgMq94wOwqJYQdgn8qzwDshzgXqMlSUtyPZjysImmktu22ew=="
1895 }, 1925 },
1896 "@types/node": { 1926 "@types/node": {
1897 - "version": "13.7.2",  
1898 - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.2.tgz",  
1899 - "integrity": "sha512-uvilvAQbdJvnSBFcKJ2td4016urcGvsiR+N4dHGU87ml8O2Vl6l+ErOi9w0kXSPiwJ1AYlIW+0pDXDWWMOiWbw==", 1927 + "version": "13.7.6",
  1928 + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.6.tgz",
  1929 + "integrity": "sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==",
1900 "dev": true 1930 "dev": true
1901 }, 1931 },
1902 "@types/prop-types": { 1932 "@types/prop-types": {
@@ -8240,6 +8270,47 @@ @@ -8240,6 +8270,47 @@
8240 "invert-kv": "^2.0.0" 8270 "invert-kv": "^2.0.0"
8241 } 8271 }
8242 }, 8272 },
  8273 + "leaflet": {
  8274 + "version": "1.6.0",
  8275 + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.6.0.tgz",
  8276 + "integrity": "sha512-CPkhyqWUKZKFJ6K8umN5/D2wrJ2+/8UIpXppY7QDnUZW5bZL5+SEI2J7GBpwh4LIupOKqbNSQXgqmrEJopHVNQ=="
  8277 + },
  8278 + "leaflet-geometryutil": {
  8279 + "version": "0.9.3",
  8280 + "resolved": "https://registry.npmjs.org/leaflet-geometryutil/-/leaflet-geometryutil-0.9.3.tgz",
  8281 + "integrity": "sha512-Wi6YvfNx/Xu9q35AEfXpsUXmIFLen/MO+C2qimxHRnjyeyOxBhdcZa6kSiReaOX0cGK7yQInqrzz0dkIqZ8Dpg==",
  8282 + "requires": {
  8283 + "leaflet": ">=0.7.0"
  8284 + }
  8285 + },
  8286 + "leaflet-polylinedecorator": {
  8287 + "version": "1.6.0",
  8288 + "resolved": "https://registry.npmjs.org/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz",
  8289 + "integrity": "sha1-nvef0bUwLWe3Lv6Vmo7NJVPycmY=",
  8290 + "requires": {
  8291 + "leaflet-rotatedmarker": "^0.2.0"
  8292 + }
  8293 + },
  8294 + "leaflet-providers": {
  8295 + "version": "1.9.1",
  8296 + "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.9.1.tgz",
  8297 + "integrity": "sha512-YpJB9y4/nT5NGicU9vuqlttJaCer6paD3J3b8Wrw+IIQvK9dtcdzE9CsTkDg7Dg9FeGp5NEr3hu17xcHbYI/2w=="
  8298 + },
  8299 + "leaflet-rotatedmarker": {
  8300 + "version": "0.2.0",
  8301 + "resolved": "https://registry.npmjs.org/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz",
  8302 + "integrity": "sha1-RGf0n5jRv9VpWb2cZwUgPdJgEnc="
  8303 + },
  8304 + "leaflet.gridlayer.googlemutant": {
  8305 + "version": "0.8.0",
  8306 + "resolved": "https://registry.npmjs.org/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.8.0.tgz",
  8307 + "integrity": "sha512-Ain+jgDKRhlM6qNDDj2QFJa9vXUqV096N0PmpHO3DoNLS4I7EynTQCJXN+9qY4C51ZpV4Q4CI+apNv5XiP5aUA=="
  8308 + },
  8309 + "leaflet.markercluster": {
  8310 + "version": "1.4.1",
  8311 + "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.4.1.tgz",
  8312 + "integrity": "sha512-ZSEpE/EFApR0bJ1w/dUGwTSUvWlpalKqIzkaYdYB7jaftQA/Y2Jav+eT4CMtEYFj+ZK4mswP13Q2acnPBnhGOw=="
  8313 + },
8243 "less": { 8314 "less": {
8244 "version": "3.10.3", 8315 "version": "3.10.3",
8245 "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", 8316 "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz",
@@ -56,6 +56,12 @@ @@ -56,6 +56,12 @@
56 "json-schema-defaults": "^0.4.0", 56 "json-schema-defaults": "^0.4.0",
57 "jstree": "^3.3.9", 57 "jstree": "^3.3.9",
58 "jstree-bootstrap-theme": "^1.0.1", 58 "jstree-bootstrap-theme": "^1.0.1",
  59 + "leaflet": "^1.6.0",
  60 + "leaflet-geometryutil": "^0.9.3",
  61 + "leaflet-polylinedecorator": "^1.6.0",
  62 + "leaflet-providers": "^1.9.1",
  63 + "leaflet.gridlayer.googlemutant": "^0.8.0",
  64 + "leaflet.markercluster": "^1.4.1",
59 "material-design-icons": "^3.0.1", 65 "material-design-icons": "^3.0.1",
60 "messageformat": "^2.3.0", 66 "messageformat": "^2.3.0",
61 "moment": "^2.24.0", 67 "moment": "^2.24.0",
@@ -99,7 +105,9 @@ @@ -99,7 +105,9 @@
99 "@types/jquery": "^3.3.32", 105 "@types/jquery": "^3.3.32",
100 "@types/js-beautify": "^1.8.1", 106 "@types/js-beautify": "^1.8.1",
101 "@types/jstree": "^3.3.39", 107 "@types/jstree": "^3.3.39",
102 - "@types/node": "^13.7.2", 108 + "@types/leaflet": "^1.5.9",
  109 + "@types/leaflet-polylinedecorator": "^1.6.0",
  110 + "@types/lodash": "^4.14.149",
103 "@types/raphael": "^2.1.30", 111 "@types/raphael": "^2.1.30",
104 "@types/react": "^16.9.20", 112 "@types/react": "^16.9.20",
105 "@types/react-dom": "^16.9.5", 113 "@types/react-dom": "^16.9.5",
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { JsonSchema, JsonSettingsSchema } from '@app/shared/public-api';
  18 +
  19 +
  20 +export function initSchema(): JsonSettingsSchema {
  21 + return {
  22 + schema: {
  23 + type: 'object',
  24 + properties: {},
  25 + required: []
  26 + },
  27 + form: [],
  28 + groupInfoes: []
  29 + };
  30 +}
  31 +
  32 +export function addGroupInfo(schema: JsonSettingsSchema, title: string) {
  33 + schema.groupInfoes.push({
  34 + formIndex: schema.groupInfoes?.length || 0,
  35 + GroupTitle: title
  36 + });
  37 +}
  38 +
  39 +export function addToSchema(schema: JsonSettingsSchema, newSchema: JsonSettingsSchema) {
  40 + Object.assign(schema.schema.properties, newSchema.schema.properties);
  41 + schema.schema.required = schema.schema.required.concat(newSchema.schema.required);
  42 + schema.form.push(newSchema.form);
  43 +}
  44 +
  45 +export function mergeSchemes(schemes: JsonSettingsSchema[]): JsonSettingsSchema {
  46 + return schemes.reduce((finalSchema: JsonSettingsSchema, schema: JsonSettingsSchema) => {
  47 + return {
  48 + schema: {
  49 + properties: {
  50 + ...finalSchema.schema.properties,
  51 + ...schema.schema.properties
  52 + },
  53 + required: [
  54 + ...finalSchema.schema.required,
  55 + ...schema.schema.required
  56 + ]
  57 + },
  58 + form: [
  59 + ...finalSchema.form,
  60 + ...schema.form
  61 + ]
  62 + } as JsonSettingsSchema;
  63 + }, initSchema());
  64 +}
  65 +
  66 +export function addCondition(schema: JsonSettingsSchema, condition: String): JsonSettingsSchema {
  67 + schema.form = schema.form.map(element => {
  68 + if (typeof element === 'string') {
  69 + return {
  70 + key: element,
  71 + condition
  72 + }
  73 + }
  74 + if (typeof element == 'object') {
  75 + if (element.condition) {
  76 + element.condition += ' && ' + condition
  77 + }
  78 + else element.condition = condition;
  79 + }
  80 + return element;
  81 + });
  82 + return schema;
  83 +}
@@ -15,8 +15,8 @@ @@ -15,8 +15,8 @@
15 /// 15 ///
16 16
17 import _ from 'lodash'; 17 import _ from 'lodash';
18 -import { Observable, Subject } from 'rxjs';  
19 -import { finalize, share } from 'rxjs/operators'; 18 +import { Observable, Subject, from, fromEvent, of } from 'rxjs';
  19 +import { finalize, share, map } from 'rxjs/operators';
20 import base64js from 'base64-js'; 20 import base64js from 'base64-js';
21 21
22 export function onParentScrollOrWindowResize(el: Node): Observable<Event> { 22 export function onParentScrollOrWindowResize(el: Node): Observable<Event> {
@@ -101,7 +101,7 @@ export function isNumber(value: any): boolean { @@ -101,7 +101,7 @@ export function isNumber(value: any): boolean {
101 } 101 }
102 102
103 export function isNumeric(value: any): boolean { 103 export function isNumeric(value: any): boolean {
104 - return (value - parseFloat( value ) + 1) >= 0; 104 + return (value - parseFloat(value) + 1) >= 0;
105 } 105 }
106 106
107 export function isString(value: any): boolean { 107 export function isString(value: any): boolean {
@@ -221,6 +221,18 @@ function scrollParents(node: Node): Node[] { @@ -221,6 +221,18 @@ function scrollParents(node: Node): Node[] {
221 return scrollParentNodes; 221 return scrollParentNodes;
222 } 222 }
223 223
  224 +function hashCode(str) {
  225 + let hash = 0;
  226 + let i, char;
  227 + if (str.length == 0) return hash;
  228 + for (i = 0; i < str.length; i++) {
  229 + char = str.charCodeAt(i);
  230 + hash = ((hash << 5) - hash) + char;
  231 + hash = hash & hash; // Convert to 32bit integer
  232 + }
  233 + return hash;
  234 +}
  235 +
224 function easeInOut( 236 function easeInOut(
225 currentTime: number, 237 currentTime: number,
226 startTime: number, 238 startTime: number,
@@ -411,3 +423,147 @@ export function snakeCase(name: string, separator: string): string { @@ -411,3 +423,147 @@ export function snakeCase(name: string, separator: string): string {
411 export function getDescendantProp(obj: any, path: string): any { 423 export function getDescendantProp(obj: any, path: string): any {
412 return path.split('.').reduce((acc, part) => acc && acc[part], obj); 424 return path.split('.').reduce((acc, part) => acc && acc[part], obj);
413 } 425 }
  426 +
  427 +export function imageLoader(imageUrl: string): Observable<HTMLImageElement> {
  428 + const image = new Image();
  429 + const imageLoad$ = fromEvent(image, 'load').pipe(map(event => image));
  430 + image.src = imageUrl;
  431 + return imageLoad$;
  432 +}
  433 +
  434 +const imageAspectMap = {};
  435 +
  436 +export function aspectCache(imageUrl: string): Observable<number> {
  437 + if (imageUrl?.length) {
  438 + const hash = hashCode(imageUrl);
  439 + let aspect = imageAspectMap[hash];
  440 + if (aspect) {
  441 + return of(aspect);
  442 + }
  443 + else return imageLoader(imageUrl).pipe(map(image => {
  444 + aspect = image.width / image.height;
  445 + imageAspectMap[hash] = aspect;
  446 + return aspect;
  447 + }))
  448 + }
  449 +}
  450 +
  451 +
  452 +export function parseArray(input: any[]): any[] {
  453 + const alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value();
  454 + return alliases.map((alliasArray, dsIndex) =>
  455 + alliasArray[0].data.map((el, i) => {
  456 + const obj = {
  457 + aliasName: alliasArray[0]?.datasource?.aliasName,
  458 + entityName: alliasArray[0]?.datasource?.entityName,
  459 + $datasource: alliasArray[0]?.datasource,
  460 + dsIndex,
  461 + time: el[0],
  462 + deviceType: null
  463 + };
  464 + alliasArray.forEach(el => {
  465 + obj[el?.dataKey?.label] = el?.data[i][1];
  466 + obj[el?.dataKey?.label + '|ts'] = el?.data[0][0];
  467 + if (el?.dataKey?.label === 'type') {
  468 + obj.deviceType = el?.data[0][1];
  469 + }
  470 + });
  471 + return obj;
  472 + })
  473 + );
  474 +}
  475 +
  476 +export function parseData(input: any[]): any[] {
  477 + return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map((alliasArray, i) => {
  478 + const obj = {
  479 + aliasName: alliasArray[0]?.datasource?.aliasName,
  480 + entityName: alliasArray[0]?.datasource?.entityName,
  481 + $datasource: alliasArray[0]?.datasource,
  482 + dsIndex: i,
  483 + deviceType: null
  484 + };
  485 + alliasArray.forEach(el => {
  486 + obj[el?.dataKey?.label] = el?.data[0][1];
  487 + obj[el?.dataKey?.label + '|ts'] = el?.data[0][0];
  488 + if (el?.dataKey?.label === 'type') {
  489 + obj.deviceType = el?.data[0][1];
  490 + }
  491 + });
  492 + return obj;
  493 + });
  494 +}
  495 +
  496 +export function safeExecute(func: Function, params = []) {
  497 + let res = null;
  498 + if (func && typeof (func) === 'function') {
  499 + try {
  500 + res = func(...params);
  501 + }
  502 + catch (err) {
  503 + console.log('error in external function:', err);
  504 + res = null;
  505 + }
  506 + }
  507 + return res;
  508 +}
  509 +
  510 +export function parseFunction(source: any, params: string[] = []): Function {
  511 + let res = null;
  512 + if (source?.length) {
  513 + try {
  514 + res = new Function(...params, source);
  515 + }
  516 + catch (err) {
  517 + console.error(err);
  518 + res = null;
  519 + }
  520 + }
  521 + return res;
  522 +}
  523 +
  524 +export function parseTemplate(template: string, data: object) {
  525 + let res = '';
  526 + try {
  527 + let variables = '';
  528 + const expressions = template
  529 + .match(/\{(.*?)\}/g) // find expressions
  530 + .map(exp => exp.replace(/{|}/g, '')) // remove brackets
  531 + .map(exp => exp.split(':'))
  532 + .map(arr => {
  533 + variables += `let ${arr[0]} = ''; `;
  534 + return arr;
  535 + })
  536 + .filter(arr => !!arr[1]) // filter expressions without format
  537 + .reduce((res, current) => {
  538 + res[current[0]] = current[1];
  539 + return res;
  540 + }, {});
  541 +
  542 + for (const key in data) {
  543 + if (!key.includes('|'))
  544 + variables += `${key} = '${expressions[key] ? padValue(data[key], +expressions[key]) : data[key]}';`;
  545 + }
  546 + template = template.replace(/:\d+}/g, '}');
  547 + res = safeExecute(parseFunction(variables + 'return' + '`' + template + '`'));
  548 + }
  549 + catch (ex) {
  550 + }
  551 + return res;
  552 +}
  553 +
  554 +export function padValue(val: any, dec: number): string {
  555 + let strVal;
  556 + let n;
  557 +
  558 + val = parseFloat(val);
  559 + n = (val < 0);
  560 + val = Math.abs(val);
  561 +
  562 + if (dec > 0) {
  563 + strVal = val.toFixed(dec).toString()
  564 + } else {
  565 + strVal = Math.round(val).toString();
  566 + }
  567 + strVal = (n ? '-' : '') + strVal;
  568 + return strVal;
  569 +}
@@ -18,7 +18,7 @@ import * as CanvasGauges from 'canvas-gauges'; @@ -18,7 +18,7 @@ import * as CanvasGauges from 'canvas-gauges';
18 import { FontStyle, FontWeight } from '@home/components/widget/lib/settings.models'; 18 import { FontStyle, FontWeight } from '@home/components/widget/lib/settings.models';
19 import * as tinycolor_ from 'tinycolor2'; 19 import * as tinycolor_ from 'tinycolor2';
20 import { ColorFormats } from 'tinycolor2'; 20 import { ColorFormats } from 'tinycolor2';
21 -import { isDefined, isString, isUndefined } from '@core/utils'; 21 +import { isDefined, isString, isUndefined, padValue } from '@core/utils';
22 import GenericOptions = CanvasGauges.GenericOptions; 22 import GenericOptions = CanvasGauges.GenericOptions;
23 import BaseGauge = CanvasGauges.BaseGauge; 23 import BaseGauge = CanvasGauges.BaseGauge;
24 24
@@ -786,24 +786,6 @@ function drawDigitalMinMax(context: DigitalGaugeCanvasRenderingContext2D, option @@ -786,24 +786,6 @@ function drawDigitalMinMax(context: DigitalGaugeCanvasRenderingContext2D, option
786 drawText(context, options, 'MinMax', options.maxValue+'', maxX, maxY); 786 drawText(context, options, 'MinMax', options.maxValue+'', maxX, maxY);
787 } 787 }
788 788
789 -function padValue(val: any, options: CanvasDigitalGaugeOptions): string {  
790 - const dec = options.valueDec;  
791 - let strVal;  
792 - let n;  
793 -  
794 - val = parseFloat(val);  
795 - n = (val < 0);  
796 - val = Math.abs(val);  
797 -  
798 - if (dec > 0) {  
799 - strVal = val.toFixed(dec).toString()  
800 - } else {  
801 - strVal = Math.round(val).toString();  
802 - }  
803 - strVal = (n ? '-' : '') + strVal;  
804 - return strVal;  
805 -}  
806 -  
807 function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, value: any) { 789 function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, value: any) {
808 if (options.hideValue) return; 790 if (options.hideValue) return;
809 791
@@ -813,7 +795,7 @@ function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options @@ -813,7 +795,7 @@ function drawDigitalValue(context: DigitalGaugeCanvasRenderingContext2D, options
813 const textX = Math.round(baseX + width / 2); 795 const textX = Math.round(baseX + width / 2);
814 const textY = valueY; 796 const textY = valueY;
815 797
816 - let text = options.valueText || padValue(value, options); 798 + let text = options.valueText || padValue(value, options.valueDec);
817 text += options.symbol; 799 text += options.symbol;
818 800
819 context.save(); 801 context.save();
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +
  19 +import 'leaflet-providers';
  20 +import 'leaflet.markercluster/dist/MarkerCluster.css'
  21 +import 'leaflet.markercluster/dist/MarkerCluster.Default.css'
  22 +import 'leaflet.markercluster/dist/leaflet.markercluster'
  23 +
  24 +import { MapSettings, MarkerSettings, FormattedData, UnitedMapSettings, PolygonSettings } from './map-models';
  25 +import { Marker } from './markers';
  26 +import { Observable, of, BehaviorSubject, Subject } from 'rxjs';
  27 +import { filter } from 'rxjs/operators';
  28 +import { Polyline } from './polyline';
  29 +import { Polygon } from './polygon';
  30 +
  31 +export default abstract class LeafletMap {
  32 +
  33 + markers: Map<string, Marker> = new Map();
  34 + dragMode = true;
  35 + poly: Polyline;
  36 + polygon: Polygon;
  37 + map: L.Map;
  38 + map$: BehaviorSubject<L.Map> = new BehaviorSubject(null);
  39 + ready$: Observable<L.Map> = this.map$.pipe(filter(map => !!map));
  40 + options: UnitedMapSettings;
  41 + isMarketCluster: boolean;
  42 + bounds: L.LatLngBounds;
  43 + newMarker: L.Marker;
  44 + datasources: FormattedData[];
  45 +
  46 + constructor(public $container: HTMLElement, options: UnitedMapSettings) {
  47 + this.options = options;
  48 + }
  49 +
  50 + public initSettings(options: MapSettings) {
  51 + const { initCallback,
  52 + disableScrollZooming, }: MapSettings = options;
  53 + if (disableScrollZooming) {
  54 + this.map.scrollWheelZoom.disable();
  55 + }
  56 + if (initCallback) {
  57 + setTimeout(options.initCallback, 0);
  58 + }
  59 + }
  60 +
  61 + addMarkerControl() {
  62 + if (this.options.draggableMarker) {
  63 + let mousePositionOnMap: L.LatLng;
  64 + let addMarker: L.Control;
  65 + this.map.on('mouseup', (e: L.LeafletMouseEvent) => {
  66 + mousePositionOnMap = e.latlng
  67 + })
  68 + const dragListener = (e: L.DragEndEvent) => {
  69 + if (e.type === 'dragend' && mousePositionOnMap) {
  70 + const newMarker = L.marker(mousePositionOnMap).addTo(this.map);
  71 + const datasourcesList = document.createElement('div');
  72 + const customLatLng = this.convertToCustomFormat(mousePositionOnMap);
  73 + this.datasources.forEach(ds => {
  74 + const dsItem = document.createElement('p');
  75 + dsItem.appendChild(document.createTextNode(ds.entityName));
  76 + dsItem.setAttribute('style', 'font-size: 14px');
  77 + dsItem.onclick = () => {
  78 + const updatedEnttity = { ...ds, ...customLatLng };
  79 + this.saveMarkerLocation(updatedEnttity);
  80 + this.map.removeLayer(newMarker);
  81 + this.deleteMarker(ds.aliasName);
  82 + this.createMarker(ds.aliasName, updatedEnttity, this.datasources, this.options, false);
  83 + }
  84 + datasourcesList.append(dsItem);
  85 + })
  86 + const popup = L.popup();
  87 + popup.setContent(datasourcesList);
  88 + newMarker.bindPopup(popup).openPopup();
  89 +
  90 + }
  91 + addMarker.setPosition('topright')
  92 + }
  93 + L.Control.AddMarker = L.Control.extend({
  94 + onAdd(map) {
  95 + const img = L.DomUtil.create('img') as any;
  96 + img.src = `assets/add_location.svg`;
  97 + img.style.width = '32px';
  98 + img.style.height = '32px';
  99 + img.onclick = this.dragMarker;
  100 + img.draggable = true;
  101 + const draggableImg = new L.Draggable(img);
  102 + draggableImg.enable();
  103 + draggableImg.on('dragend', dragListener)
  104 + return img;
  105 + },
  106 + onRemove(map) {
  107 + },
  108 + dragMarker: this.dragMarker
  109 +
  110 + } as any);
  111 +
  112 + L.control.addMarker = (opts) => {
  113 + return new L.Control.AddMarker(opts);
  114 + }
  115 +
  116 + addMarker = L.control.addMarker({ position: 'topright' }).addTo(this.map);
  117 + }
  118 + }
  119 +
  120 + public setMap(map: L.Map) {
  121 + this.map = map;
  122 + if (this.options.useDefaultCenterPosition) {
  123 + this.map.panTo(this.options.defaultCenterPosition);
  124 + this.bounds = map.getBounds();
  125 + }
  126 + else this.bounds = new L.LatLngBounds(null, null);
  127 + if (this.options.draggableMarker) {
  128 + this.addMarkerControl();
  129 + }
  130 + this.map$.next(this.map);
  131 + }
  132 +
  133 + public setDataSources(dataSources) {
  134 + this.datasources = dataSources;
  135 + }
  136 +
  137 + public saveMarkerLocation(e) {
  138 +
  139 + }
  140 +
  141 + createLatLng(lat: number, lng: number): L.LatLng {
  142 + return L.latLng(lat, lng);
  143 + }
  144 +
  145 + createBounds(): L.LatLngBounds {
  146 + return this.map.getBounds();
  147 + }
  148 +
  149 + extendBounds(bounds: L.LatLngBounds, polyline: L.Polyline) {
  150 + if (polyline && polyline.getLatLngs() && polyline.getBounds()) {
  151 + bounds.extend(polyline.getBounds());
  152 + }
  153 + }
  154 +
  155 + invalidateSize() {
  156 + this.map?.invalidateSize(true);
  157 + }
  158 +
  159 + onResize() {
  160 +
  161 + }
  162 +
  163 + getCenter() {
  164 + return this.map.getCenter();
  165 + }
  166 +
  167 + convertPosition(expression: object): L.LatLng {
  168 + const lat = expression[this.options.latKeyName];
  169 + const lng = expression[this.options.lngKeyName];
  170 + if (isNaN(lat) || isNaN(lng))
  171 + return null;
  172 + else
  173 + return L.latLng(lat, lng) as L.LatLng;
  174 + }
  175 +
  176 + convertToCustomFormat(position: L.LatLng): object {
  177 + return {
  178 + [this.options.latKeyName]: position.lat,
  179 + [this.options.lngKeyName]: position.lng
  180 + }
  181 + }
  182 +
  183 + // Markers
  184 + updateMarkers(markersData) {
  185 + markersData.forEach(data => {
  186 + if (this.convertPosition(data)) {
  187 + if (data.rotationAngle) {
  188 + this.options.icon = L.divIcon({
  189 + html: `<div class="arrow" style="transform: rotate(${data.rotationAngle}deg)"><div>`
  190 + })
  191 + }
  192 + else {
  193 + this.options.icon = null;
  194 + }
  195 + if (this.markers.get(data.aliasName)) {
  196 + this.updateMarker(data.aliasName, data, markersData, this.options)
  197 + }
  198 + else {
  199 + this.createMarker(data.aliasName, data, markersData, this.options as MarkerSettings);
  200 + }
  201 + }
  202 + });
  203 + }
  204 +
  205 + dragMarker = (e, data?) => {
  206 + if (e.type !== 'dragend') return;
  207 + this.saveMarkerLocation({ ...data, ...this.convertToCustomFormat(e.target._latlng) });
  208 + }
  209 +
  210 + private createMarker(key, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings, setFocus = true) {
  211 + this.ready$.subscribe(() => {
  212 + const newMarker = new Marker(this.map, this.convertPosition(data), settings, data, dataSources, () => { }, this.dragMarker);
  213 + if (setFocus)
  214 + this.map.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()));
  215 + this.markers.set(key, newMarker);
  216 + });
  217 + }
  218 +
  219 + private updateMarker(key, data, dataSources, settings: MarkerSettings) {
  220 + const marker: Marker = this.markers.get(key);
  221 + const location = this.convertPosition(data)
  222 + if (!location.equals(marker.location)) {
  223 + marker.updateMarkerPosition(location);
  224 + }
  225 + if (settings.showTooltip) {
  226 + marker.updateMarkerTooltip(data);
  227 + }
  228 + marker.setDataSources(data, dataSources);
  229 + marker.updateMarkerIcon(settings);
  230 + }
  231 +
  232 + deleteMarker(key) {
  233 + let marker = this.markers.get(key)?.leafletMarker;
  234 + if (marker) {
  235 + this.map.removeLayer(marker);
  236 + this.markers.delete(key);
  237 + marker = null;
  238 + }
  239 + }
  240 +
  241 + // Polyline
  242 +
  243 + updatePolylines(polyData: Array<Array<any>>) {
  244 + polyData.forEach(data => {
  245 + if (data.length) {
  246 + const dataSource = polyData.map(arr => arr[0]);
  247 + if (this.poly) {
  248 + this.updatePolyline(data, dataSource, this.options);
  249 + }
  250 + else {
  251 + this.createPolyline(data, dataSource, this.options);
  252 + }
  253 + }
  254 + })
  255 + }
  256 +
  257 + createPolyline(data: any[], dataSources, settings) {
  258 + if (data.length)
  259 + this.ready$.subscribe(() => {
  260 + this.poly = new Polyline(this.map,
  261 + data.map(el => this.convertPosition(el)).filter(el => !!el), data, dataSources, settings);
  262 + const bounds = this.bounds.extend(this.poly.leafletPoly.getBounds());
  263 + if (bounds.isValid()) {
  264 + this.map.fitBounds(bounds);
  265 + this.bounds = bounds;
  266 + }
  267 + });
  268 + }
  269 +
  270 + updatePolyline(data, dataSources, settings) {
  271 + this.ready$.subscribe(() => {
  272 + this.poly.updatePolyline(settings, data, dataSources);
  273 + });
  274 + }
  275 +
  276 + // Polygon
  277 +
  278 + updatePolygons(polyData: any[]) {
  279 + polyData.forEach((data: any) => {
  280 + if (data.data.length && data.dataKey.name === this.options.polygonKeyName) {
  281 + if (typeof (data?.data[0][1]) === 'string') {
  282 + data.data = JSON.parse(data.data[0][1]);
  283 + }
  284 + if (this.polygon) {
  285 + this.updatePolygon(data.data, polyData, this.options);
  286 + }
  287 + else {
  288 + this.createPolygon(data.data, polyData, this.options);
  289 + }
  290 + }
  291 + });
  292 + }
  293 +
  294 + createPolygon(data: FormattedData, dataSources: FormattedData[], settings: PolygonSettings) {
  295 + this.ready$.subscribe(() => {
  296 + this.polygon = new Polygon(this.map, data, dataSources, settings);
  297 + const bounds = this.bounds.extend(this.polygon.leafletPoly.getBounds());
  298 + if (bounds.isValid()) {
  299 + this.map.fitBounds(bounds);
  300 + this.bounds = bounds;
  301 + }
  302 + });
  303 + }
  304 +
  305 + updatePolygon(data, dataSources, settings) {
  306 + this.ready$.subscribe(() => {
  307 + // this.polygon.updatePolygon(settings, data, dataSources);
  308 + });
  309 + }
  310 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License; Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing; software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS;
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND; either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { LatLngTuple } from 'leaflet';
  18 +
  19 +export type GenericFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
  20 +export type MarkerImageFunction = (data: FormattedData, dsData: FormattedData[], dsIndex: number) => string;
  21 +
  22 +export type MapSettings = {
  23 + polygonKeyName: any;
  24 + draggableMarker: boolean;
  25 + initCallback?: () => any;
  26 + defaultZoomLevel?: number;
  27 + dontFitMapBounds?: boolean;
  28 + disableScrollZooming?: boolean;
  29 + minZoomLevel?: number;
  30 + latKeyName?: string;
  31 + lngKeyName?: string;
  32 + xPosKeyName?: string;
  33 + yPosKeyName?: string;
  34 + mapProvider: MapProviders;
  35 + mapUrl?: string;
  36 + mapImageUrl?: string;
  37 + provider?: MapProviders;
  38 + credentials?: any; // declare credentials format
  39 + defaultCenterPosition?: LatLngTuple;
  40 + markerClusteringSetting?;
  41 + useDefaultCenterPosition?: boolean;
  42 + gmDefaultMapType?: string;
  43 + useLabelFunction: string;
  44 + icon?: any;
  45 +}
  46 +
  47 +export enum MapProviders {
  48 + google = 'google-map',
  49 + openstreet = 'openstreet-map',
  50 + here = 'here',
  51 + image = 'image-map',
  52 + tencent = 'tencent-map'
  53 +}
  54 +
  55 +export type MarkerSettings = {
  56 + tooltipPattern?: any;
  57 + icon?: any;
  58 + showLabel?: boolean;
  59 + label: string;
  60 + labelColor: string;
  61 + labelText: string;
  62 + useLabelFunction: boolean;
  63 + draggableMarker: boolean;
  64 + showTooltip?: boolean;
  65 + color?: string;
  66 + autocloseTooltip: boolean;
  67 + displayTooltipAction: string;
  68 + currentImage?: string;
  69 + useMarkerImageFunction?: boolean;
  70 + markerImages?: string[];
  71 + useMarkerImage: boolean;
  72 + markerImageSize: number;
  73 + markerImage: {
  74 + length: number
  75 + }
  76 +
  77 + colorFunction: GenericFunction;
  78 + tooltipFunction: GenericFunction;
  79 + labelFunction: GenericFunction;
  80 + markerImageFunction?: MarkerImageFunction;
  81 +}
  82 +
  83 +export interface FormattedData {
  84 + aliasName: string;
  85 + entityName: string;
  86 + $datasource: string;
  87 + dsIndex: number;
  88 + deviceType: string
  89 +}
  90 +
  91 +export type PolygonSettings = {
  92 + showPolygon: boolean;
  93 + showTooltip: any;
  94 + polygonStrokeOpacity: number;
  95 + polygonOpacity: number;
  96 + polygonStrokeWeight: number;
  97 + polygonStrokeColor: string;
  98 + polygonColor: string;
  99 + autocloseTooltip: boolean;
  100 + displayTooltipAction: string;
  101 +
  102 + polygonColorFunction?: GenericFunction;
  103 +}
  104 +
  105 +export type PolylineSettings = {
  106 + usePolylineDecorator: any;
  107 + autocloseTooltip: boolean;
  108 + displayTooltipAction: string;
  109 + useColorFunction: any;
  110 + color: string;
  111 + useStrokeOpacityFunction: any;
  112 + strokeOpacity: number;
  113 + useStrokeWeightFunction: any;
  114 + strokeWeight: number;
  115 + decoratorOffset: string | number;
  116 + endDecoratorOffset: string | number;
  117 + decoratorRepeat: string | number;
  118 + decoratorSymbol: any;
  119 + decoratorSymbolSize: any;
  120 + useDecoratorCustomColor: any;
  121 + decoratorCustomColor: any;
  122 +
  123 +
  124 + colorFunction: GenericFunction;
  125 + strokeOpacityFunction: GenericFunction;
  126 + strokeWeightFunction: GenericFunction;
  127 +}
  128 +
  129 +export interface HistorySelectSettings {
  130 + buttonColor: string;
  131 +}
  132 +
  133 +export type UnitedMapSettings = MapSettings & PolygonSettings & MarkerSettings & PolygonSettings;
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { JsonSettingsSchema } from '@app/shared/public-api';
  18 +
  19 +export interface MapWidgetInterface {
  20 + resize(),
  21 + update(),
  22 + onInit(),
  23 + onDestroy();
  24 +}
  25 +
  26 +export interface MapWidgetStaticInterface {
  27 + settingsSchema(mapProvider?, drawRoutes?): JsonSettingsSchema;
  28 + getProvidersSchema():JsonSettingsSchema
  29 + dataKeySettingsSchema(): object;
  30 + actionSources(): object;
  31 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { MapProviders, UnitedMapSettings } from './map-models';
  18 +import LeafletMap from './leaflet-map';
  19 +import {
  20 + openstreetMapSettingsSchema,
  21 + googleMapSettingsSchema,
  22 + imageMapSettingsSchema,
  23 + tencentMapSettingsSchema,
  24 + commonMapSettingsSchema,
  25 + routeMapSettingsSchema,
  26 + markerClusteringSettingsSchema,
  27 + markerClusteringSettingsSchemaLeaflet,
  28 + hereMapSettingsSchema,
  29 + mapProviderSchema
  30 +} from './schemes';
  31 +import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface';
  32 +import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers';
  33 +import { parseFunction, parseArray, parseData } from '@app/core/utils';
  34 +import { initSchema, addToSchema, mergeSchemes, addCondition, addGroupInfo } from '@app/core/schema-utils';
  35 +import { AttributeScope, EntityId, JsonSettingsSchema } from '@app/shared/public-api';
  36 +import { forkJoin } from 'rxjs';
  37 +import { WidgetContext } from '@app/modules/home/models/widget-component.models';
  38 +import { AttributeService } from '@app/core/public-api';
  39 +import { getDefCenterPosition } from './maps-utils';
  40 +
  41 +let providerSets;
  42 +let defaultSettings;
  43 +
  44 +export class MapWidgetController implements MapWidgetInterface {
  45 +
  46 + constructor(public mapProvider: MapProviders, private drawRoutes: boolean, public ctx: WidgetContext, $element: HTMLElement) {
  47 + if (this.map) {
  48 + this.map.map.remove();
  49 + delete this.map;
  50 + }
  51 +
  52 + this.data = ctx.data;
  53 + if (!$element) {
  54 + $element = ctx.$container[0];
  55 + }
  56 + this.settings = this.initSettings(ctx.settings);
  57 +
  58 + const MapClass = providerSets[this.provider]?.MapClass;
  59 + if (!MapClass) {
  60 + return;
  61 + }
  62 + this.map = new MapClass($element, this.settings);
  63 + this.map.saveMarkerLocation = this.setMarkerLocation;
  64 + }
  65 +
  66 + map: LeafletMap;
  67 + provider: MapProviders;
  68 + schema: JsonSettingsSchema;
  69 + data;
  70 + settings: UnitedMapSettings;
  71 +
  72 + public static dataKeySettingsSchema(): object {
  73 + return {};
  74 + }
  75 +
  76 + public static getProvidersSchema() {
  77 + return mergeSchemes([mapProviderSchema,
  78 + ...Object.values(providerSets)?.map(
  79 + (setting: IProvider) => addCondition(setting?.schema, `model.provider === '${setting.name}'`))]);
  80 + }
  81 +
  82 + public static settingsSchema(mapProvider: MapProviders, drawRoutes: boolean): JsonSettingsSchema {
  83 + const schema = initSchema();
  84 + addToSchema(schema, this.getProvidersSchema());
  85 + addGroupInfo(schema, 'Map Provider Settings');
  86 + addToSchema(schema, commonMapSettingsSchema);
  87 + addGroupInfo(schema, 'Common Map Settings');
  88 +
  89 + if (drawRoutes) {
  90 + addToSchema(schema, routeMapSettingsSchema);
  91 + addGroupInfo(schema, 'Route Map Settings');
  92 + } else if (mapProvider !== 'image-map') {
  93 + const clusteringSchema = mergeSchemes([markerClusteringSettingsSchemaLeaflet, markerClusteringSettingsSchema])
  94 + addToSchema(schema, clusteringSchema);
  95 + addGroupInfo(schema, 'Markers Clustering Settings');
  96 + }
  97 + return schema;
  98 + }
  99 +
  100 + public static actionSources(): object {
  101 + return {
  102 + markerClick: {
  103 + name: 'widget-action.marker-click',
  104 + multiple: false
  105 + },
  106 + polygonClick: {
  107 + name: 'widget-action.polygon-click',
  108 + multiple: false
  109 + },
  110 + tooltipAction: {
  111 + name: 'widget-action.tooltip-tag-action',
  112 + multiple: true
  113 + }
  114 + };
  115 + }
  116 +
  117 + onInit() {
  118 + }
  119 +
  120 + setMarkerLocation = (e) => {
  121 + const attributeService = this.ctx.$injector.get(AttributeService);
  122 + forkJoin(
  123 + this.data.filter(data => !!e[data.dataKey.name])
  124 + .map(data => {
  125 + const entityId: EntityId = {
  126 + entityType: data.datasource.entityType,
  127 + id: data.datasource.entityId
  128 + };
  129 + return attributeService.saveEntityAttributes(
  130 + entityId,
  131 + AttributeScope.SHARED_SCOPE,
  132 + [{
  133 + key: data.dataKey.name,
  134 + value: e[data.dataKey.name]
  135 + }]
  136 + );
  137 + })).subscribe(res => {
  138 + console.log('MapWidgetController -> setMarkerLocation -> res', res)
  139 + });
  140 + }
  141 +
  142 + initSettings(settings: UnitedMapSettings) {
  143 + const functionParams = ['data', 'dsData', 'dsIndex'];
  144 + this.provider = settings.provider || this.mapProvider;
  145 + const customOptions = {
  146 + provider: this.provider,
  147 + mapUrl: settings?.mapImageUrl,
  148 + labelFunction: parseFunction(settings.labelFunction, functionParams),
  149 + tooltipFunction: parseFunction(settings.tooltipFunction, functionParams),
  150 + colorFunction: parseFunction(settings.colorFunction, functionParams),
  151 + polygonColorFunction: parseFunction(settings.polygonColorFunction, functionParams),
  152 + markerImageFunction: parseFunction(settings.markerImageFunction, ['data', 'images', 'dsData', 'dsIndex']),
  153 + labelColor: this.ctx.widgetConfig.color,
  154 + tooltipPattern: settings.tooltipPattern ||
  155 + '<b>${entityName}</b><br/><br/><b>Latitude:</b> ${' +
  156 + settings.latKeyName + ':7}<br/><b>Longitude:</b> ${' + settings.lngKeyName + ':7}',
  157 + defaultCenterPosition: getDefCenterPosition(settings?.defaultCenterPosition),
  158 + currentImage: (settings.useMarkerImage && settings.markerImage?.length) ? {
  159 + url: settings.markerImage,
  160 + size: settings.markerImageSize || 34
  161 + } : null
  162 + }
  163 + return { ...defaultSettings, ...settings, ...customOptions, }
  164 + }
  165 +
  166 + update() {
  167 + if (this.drawRoutes)
  168 + this.map.updatePolylines(parseArray(this.data));
  169 + if (this.settings.showPolygon) {
  170 + this.map.updatePolygons(this.data);
  171 + }
  172 + if (this.settings.draggableMarker) {
  173 + this.map.setDataSources(parseData(this.data));
  174 + }
  175 + else
  176 + this.map.updateMarkers(parseData(this.data));
  177 + }
  178 +
  179 + resize() {
  180 + this.map?.invalidateSize();
  181 + this.map.onResize();
  182 + }
  183 +
  184 + onDestroy() {
  185 + }
  186 +}
  187 +
  188 +export let TbMapWidgetV2: MapWidgetStaticInterface = MapWidgetController;
  189 +
  190 +interface IProvider {
  191 + MapClass: LeafletMap,
  192 + schema: JsonSettingsSchema,
  193 + name: string
  194 +}
  195 +
  196 +providerSets = {
  197 + 'openstreet-map': {
  198 + MapClass: OpenStreetMap,
  199 + schema: openstreetMapSettingsSchema,
  200 + name: 'openstreet-map',
  201 + },
  202 + 'tencent-map': {
  203 + MapClass: TencentMap,
  204 + schema: tencentMapSettingsSchema,
  205 + name: 'tencent-map'
  206 + },
  207 + 'google-map': {
  208 + MapClass: GoogleMap,
  209 + schema: googleMapSettingsSchema,
  210 + name: 'google-map'
  211 + },
  212 + here: {
  213 + MapClass: HEREMap,
  214 + schema: hereMapSettingsSchema,
  215 + name: 'here'
  216 + },
  217 + 'image-map': {
  218 + MapClass: ImageMap,
  219 + schema: imageMapSettingsSchema,
  220 + name: 'image-map'
  221 + }
  222 +}
  223 +
  224 +defaultSettings = {
  225 + xPosKeyName: 'xPos',
  226 + yPosKeyName: 'yPos',
  227 + markerOffsetX: 0.5,
  228 + markerOffsetY: 1,
  229 + latKeyName: 'latitude',
  230 + lngKeyName: 'longitude',
  231 + polygonKeyName: 'coordinates',
  232 + showLabel: false,
  233 + label: '${entityName}',
  234 + showTooltip: false,
  235 + useDefaultCenterPosition: false,
  236 + showTooltipAction: 'click',
  237 + autocloseTooltip: false,
  238 + showPolygon: true,
  239 + labelColor: '#000000',
  240 + color: '#FE7569',
  241 + polygonColor: '#0000ff',
  242 + polygonStrokeColor: '#fe0001',
  243 + polygonOpacity: 0.5,
  244 + polygonStrokeOpacity: 1,
  245 + polygonStrokeWeight: 1,
  246 + useLabelFunction: false,
  247 + markerImages: [],
  248 + strokeWeight: 2,
  249 + strokeOpacity: 1.0,
  250 + initCallback: () => { },
  251 + defaultZoomLevel: 8,
  252 + dontFitMapBounds: false,
  253 + disableScrollZooming: false,
  254 + minZoomLevel: 16,
  255 + credentials: '',
  256 + markerClusteringSetting: null,
  257 + draggableMarker: false
  258 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +import _ from 'lodash';
  19 +import { MarkerSettings, PolylineSettings, PolygonSettings } from './map-models';
  20 +
  21 +export function createTooltip(target: L.Layer, settings: MarkerSettings | PolylineSettings | PolygonSettings): L.Popup {
  22 + const popup = L.popup();
  23 + popup.setContent('');
  24 + target.bindPopup(popup, { autoClose: settings.autocloseTooltip, closeOnClick: false });
  25 + if (settings.displayTooltipAction === 'hover') {
  26 + target.off('click');
  27 + target.on('mouseover', function () {
  28 + this.openPopup();
  29 + });
  30 + target.on('mouseout', function () {
  31 + this.closePopup();
  32 + });
  33 + }
  34 + return popup;
  35 +}
  36 +
  37 +export function getRatio(firsMoment: number, secondMoment: number, intermediateMoment: number): number {
  38 + return (intermediateMoment - firsMoment) / (secondMoment - firsMoment);
  39 +};
  40 +
  41 +export function findAngle(startPoint, endPoint) {
  42 + let angle = -Math.atan2(endPoint.latitude - startPoint.latitude, endPoint.longitude - startPoint.longitude);
  43 + angle = angle * 180 / Math.PI;
  44 + return parseInt(angle.toFixed(2), 10);
  45 +}
  46 +
  47 +
  48 +export function getDefCenterPosition(position) {
  49 + if (typeof (position) === 'string')
  50 + return position.split(',');
  51 + if (typeof (position) === 'object')
  52 + return position;
  53 + return [0, 0];
  54 +}
  55 +
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +.arrow {
  17 + height: 30px;
  18 + width: 30px;
  19 + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAMAAAANxBKoAAACAVBMVEUAAAAAqv9AgP8ggP8udP8qgP8ndv8kbf8kgP8eeP8rcf8mc/8jdP8hev8me/8kdv8jcv8pcP8ic/8neP8leP8ofP8mef8pev8nef8oe/8nef8pef8qfv8qgf8qe/8mev8off8oev8oef8oe/8pev8qe/8oe/8off8pfP8oev8pev8qe/8qfP8pev8pe/8qfP8pe/8oev8pe/8qe/8qfP8qfP8qff8qff8qfP8qff8pe/8qff8qfP8qfP8pev8pev8JYf8KYP8UY/8UZf8WY/8WZv8YZP8bZP8fZv8fZ/8gZv8gZ/8hZP8iZ/8jaf8jav8kaP8kav8ka/8kbP8kbf8kb/8lbP8lbf8lbv8lb/8lcP8mb/8mcP8mcf8ncf8ncv8nc/8ndP8ndf8ocv4odP8odf8odv8od/8oeP8peP8pef8pev8qev8qe/8qfP8rbP8rfP8rff8tc/4vcP4xbv4zcf42dP49df4+gP4/fv5Rif5biP1ul/14mvx4nvyMrfuMrvuWsfuctvuguPuww/vD0fnH1vrI1frK2PrL2fnV3vnb4vnc5fnd5fnd5vne5fnj6vnl6/jm7Pno7fXo7fbo7ffo7fjp7fnp7vjq7vjs8fnt8Pjt8fjw8fXw8fbw8fjy8/jz9fn5+fj7+/f++/j/+/X/+/b/+/f/+/j//Pj//vhoUaHMAAAAQHRSTlMAAwQICwwNDg4REhQWFxscHTI1QkRGSktOU1RdYWFscXJzhYWKqre6wMHDw8PHx8rN09TW1uLi7e/x8vLz9fj5hfwW0QAAAnVJREFUSMeV1fdb00AYB/BzoQjurSjuvQcuFLcgWqTVtLVpL0GS2GuDuLeouPeAiLOuwOFf6WU0ucvq4/d52v6Qz/M+18u97wHgyfh5m5vUYlHt2rV8BojOqGUqonNhVgTegfxZE2JXoMAUFgXYsSoKy3YfnoIiUqxm8UwUnSoaT0WVUuPi6lCUz+ft/+pqNYwqsiwrlm8s45XBVpE7BQgFyeZLbB1ihVwmefjpDSjbi7HwziArCdlU/MArjDHfaestBh4dZs9/JBb/4kVbo5FEr/JaWRL4VPvZ39jMVV4q63qiCx7bIfDJtst/LYt/JnLldaNuACbS9JwiQj4Zu/3HlDr5nEyJivMcgPn0Nogwfaq1Z9igQ7pO9AuqNEJzQINTV5ZghjvywLFG6dYMVRptAF3uPvBc8xPsWH0Q44ccpEqjvaBoa0lI7/ts2kHdCsbDJ5jSSC2/SEU8856x+hDGd+JZujQquvp6ieT7Nyel0o/jCSgzTefq0y81I30f7PRr2i1fbWrd+98yXtMGfOt29wTyiebHpu83dZ+m3U969qSBeje5DHeod8Dx5PeYZ7/rPO8y0XLvk+1J8UcJyLzLScw5kTsgz8Xu2vXJV0uaOSfsGcznZZGcwdi1L5qV13HmDILV3tY1z3fbxa8Wv+Se74VEj/H3jmz0TvuVN4Z+x/ZORF8efU64s/CtUT0vCbk0d/DZTSgxPQ/WhswTSYTZrDNPllaaVQo1q/Y4k63mv+YgmFZxxk6gR/LsCngcO+6nR9lCrfcqqQ2/dxqD7rT1IXhxyB24O8BuCr9eq9axU7F7wYjoy3ty3TZVLaCC2rRxru/hPwVgtEdFK5vOAAAAAElFTkSuQmCC");
  20 + background-size: cover;
  21 + background-repeat: no-repeat;
  22 + background-position: center center;
  23 +}
  24 +
  25 +.leaflet-div-icon,
  26 +.tb-marker-label,
  27 +.tb-marker-label:before {
  28 + border: none;
  29 + background: none;
  30 + box-shadow: none;
  31 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +import { MarkerSettings, FormattedData } from './map-models';
  19 +import { aspectCache, safeExecute, parseTemplate } from '@app/core/utils';
  20 +import { createTooltip } from './maps-utils';
  21 +
  22 +export class Marker {
  23 +
  24 + leafletMarker: L.Marker;
  25 + tooltipOffset: [number, number];
  26 + tooltip: L.Popup;
  27 + location: L.LatLngExpression;
  28 + data: FormattedData;
  29 + dataSources: FormattedData[];
  30 +
  31 + constructor(private map: L.Map, location: L.LatLngExpression, public settings: MarkerSettings,
  32 + data?, dataSources?, onClickListener?, onDragendListener?) {
  33 + this.setDataSources(data, dataSources);
  34 + this.leafletMarker = L.marker(location, {
  35 + draggable: settings.draggableMarker
  36 + });
  37 +
  38 + this.createMarkerIcon((iconInfo) => {
  39 + this.leafletMarker.setIcon(iconInfo.icon);
  40 + this.tooltipOffset = [0, -iconInfo.size[1] + 10];
  41 + this.updateMarkerLabel(settings);
  42 + this.leafletMarker.addTo(map);
  43 + });
  44 +
  45 + if (settings.showTooltip) {
  46 + this.tooltip = createTooltip(this.leafletMarker, settings);
  47 + this.tooltip.setContent(parseTemplate(this.settings.tooltipPattern, data));
  48 + }
  49 +
  50 + if (onClickListener) {
  51 + this.leafletMarker.on('click', onClickListener);
  52 + }
  53 +
  54 + if (onDragendListener) {
  55 + this.leafletMarker.on('dragend', (e) => onDragendListener(e, this.data));
  56 + }
  57 + }
  58 +
  59 + setDataSources(data: FormattedData, dataSources: FormattedData[]) {
  60 + this.data = data;
  61 + this.dataSources = dataSources;
  62 + }
  63 +
  64 + updateMarkerTooltip(data: FormattedData) {
  65 + this.tooltip.setContent(parseTemplate(this.settings.tooltipPattern, data));
  66 + }
  67 +
  68 + updateMarkerPosition(position: L.LatLngExpression) {
  69 + this.leafletMarker.setLatLng(position);
  70 + }
  71 +
  72 + updateMarkerLabel(settings: MarkerSettings) {
  73 + this.leafletMarker.unbindTooltip();
  74 +
  75 + if (settings.showLabel) {
  76 + if (settings.useLabelFunction) {
  77 + settings.labelText = safeExecute(settings.labelFunction, [this.data, this.dataSources, this.data.dsIndex])
  78 + }
  79 + else settings.labelText = parseTemplate(settings.label, this.data);
  80 + this.leafletMarker.bindTooltip(`<div style="color: ${settings.labelColor};"><b>${settings.labelText}</b></div>`,
  81 + { className: 'tb-marker-label', permanent: true, direction: 'top', offset: this.tooltipOffset });
  82 + }
  83 + }
  84 +
  85 + updateMarkerColor(color) {
  86 + this.createDefaultMarkerIcon(color, (iconInfo) => {
  87 + this.leafletMarker.setIcon(iconInfo.icon);
  88 + });
  89 + }
  90 +
  91 + updateMarkerIcon(settings: MarkerSettings) {
  92 + this.createMarkerIcon((iconInfo) => {
  93 + this.leafletMarker.setIcon(iconInfo.icon);
  94 + this.tooltipOffset = [0, -iconInfo.size[1] + 10];
  95 + this.updateMarkerLabel(settings);
  96 + });
  97 + }
  98 +
  99 + createMarkerIcon(onMarkerIconReady) {
  100 +
  101 + if (this.settings.icon) {
  102 + onMarkerIconReady({
  103 + size: [30, 30],
  104 + icon: this.settings.icon,
  105 + });
  106 + return;
  107 + }
  108 +
  109 + const currentImage = this.settings.useMarkerImageFunction ?
  110 + safeExecute(this.settings.markerImageFunction,
  111 + [this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage;
  112 +
  113 +
  114 + if (currentImage && currentImage.url) {
  115 + aspectCache(currentImage.url).subscribe(
  116 + (aspect) => {
  117 + if (aspect) {
  118 + let width;
  119 + let height;
  120 + if (aspect > 1) {
  121 + width = currentImage.size;
  122 + height = currentImage.size / aspect;
  123 + } else {
  124 + width = currentImage.size * aspect;
  125 + height = currentImage.size;
  126 + }
  127 + const icon = L.icon({
  128 + iconUrl: currentImage.url,
  129 + iconSize: [width, height],
  130 + iconAnchor: [width / 2, height],
  131 + popupAnchor: [0, -height]
  132 + });
  133 + const iconInfo = {
  134 + size: [width, height],
  135 + icon
  136 + };
  137 + onMarkerIconReady(iconInfo);
  138 + } else {
  139 + this.createDefaultMarkerIcon(this.settings.color, onMarkerIconReady);
  140 + }
  141 + }
  142 + );
  143 + } else {
  144 + this.createDefaultMarkerIcon(this.settings.color, onMarkerIconReady);
  145 + }
  146 + }
  147 +
  148 + createDefaultMarkerIcon(color, onMarkerIconReady) {
  149 + const pinColor = color.substr(1);
  150 + const icon = L.icon({
  151 + iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + pinColor,
  152 + iconSize: [21, 34],
  153 + iconAnchor: [10, 34],
  154 + popupAnchor: [0, -34],
  155 + shadowUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_shadow',
  156 + shadowSize: [40, 37],
  157 + shadowAnchor: [12, 35]
  158 + });
  159 + const iconInfo = {
  160 + size: [21, 34],
  161 + icon
  162 + };
  163 + onMarkerIconReady(iconInfo);
  164 + }
  165 +
  166 +
  167 +
  168 + removeMarker() {
  169 + /* this.map$.subscribe(map =>
  170 + this.leafletMarker.addTo(map))*/
  171 + }
  172 +
  173 + extendBoundsWithMarker(bounds) {
  174 + bounds.extend(this.leafletMarker.getLatLng());
  175 + }
  176 +
  177 + getMarkerPosition() {
  178 + return this.leafletMarker.getLatLng();
  179 + }
  180 +
  181 + setMarkerPosition(latLng) {
  182 + this.leafletMarker.setLatLng(latLng);
  183 + }
  184 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L, { LatLngExpression } from 'leaflet';
  18 +import { createTooltip } from './maps-utils';
  19 +import { PolygonSettings } from './map-models';
  20 +
  21 +export class Polygon {
  22 +
  23 + leafletPoly: L.Polygon;
  24 + tooltip;
  25 +
  26 + constructor(public map, coordinates, dataSources, settings: PolygonSettings, onClickListener?) {
  27 + this.leafletPoly = L.polygon(coordinates, {
  28 + fill: true,
  29 + fillColor: settings.polygonColor,
  30 + color: settings.polygonStrokeColor,
  31 + weight: settings.polygonStrokeWeight,
  32 + fillOpacity: settings.polygonOpacity,
  33 + opacity: settings.polygonStrokeOpacity
  34 + }).addTo(this.map);
  35 +
  36 + if (settings.showTooltip) {
  37 + this.tooltip = createTooltip(this.leafletPoly, settings);
  38 + }
  39 + if (onClickListener) {
  40 + this.leafletPoly.on('click', onClickListener);
  41 + }
  42 + }
  43 +
  44 + removePolygon() {
  45 + this.map.removeLayer(this.leafletPoly);
  46 + }
  47 +
  48 + updatePolygonColor(settings) {
  49 + console.log('Polygon -> updatePolygonColor -> settings', settings)
  50 + const style: L.PathOptions = {
  51 +
  52 + fill: true,
  53 + fillColor: settings.color,
  54 + color: settings.color,
  55 + weight: settings.polygonStrokeWeight,
  56 + fillOpacity: settings.polygonOpacity,
  57 + opacity: settings.polygonStrokeOpacity
  58 + };
  59 + this.leafletPoly.setStyle(style);
  60 + }
  61 +
  62 + getPolygonLatLngs() {
  63 + return this.leafletPoly.getLatLngs();
  64 + }
  65 +
  66 + setPolygonLatLngs(latLngs: LatLngExpression[]) {
  67 + this.leafletPoly.setLatLngs(latLngs);
  68 + this.leafletPoly.redraw();
  69 + }
  70 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L, { PolylineDecoratorOptions } from 'leaflet';
  18 +import 'leaflet-polylinedecorator';
  19 +
  20 +import { safeExecute } from '@app/core/utils';
  21 +import { PolylineSettings } from './map-models';
  22 +
  23 +export class Polyline {
  24 +
  25 + leafletPoly: L.Polyline;
  26 + polylineDecorator: L.PolylineDecorator;
  27 + dataSources;
  28 + data;
  29 +
  30 + constructor(private map: L.Map, locations, data, dataSources, settings: PolylineSettings) {
  31 + this.dataSources = dataSources;
  32 + this.data = data;
  33 +
  34 + this.leafletPoly = L.polyline(locations,
  35 + this.getPolyStyle(settings)
  36 + ).addTo(this.map);
  37 + if (settings.usePolylineDecorator) {
  38 + this.polylineDecorator = L.polylineDecorator(this.leafletPoly, this.getDecoratorSettings(settings)).addTo(this.map);
  39 + }
  40 + }
  41 +
  42 + getDecoratorSettings(settings: PolylineSettings): PolylineDecoratorOptions {
  43 + return {
  44 + patterns: [
  45 + {
  46 + offset: settings.decoratorOffset,
  47 + endOffset: settings.endDecoratorOffset,
  48 + repeat: settings.decoratorRepeat,
  49 + symbol: L.Symbol[settings.decoratorSymbol]({
  50 + pixelSize: settings.decoratorSymbolSize,
  51 + polygon: false,
  52 + pathOptions: {
  53 + color: settings.useDecoratorCustomColor ? settings.decoratorCustomColor : this.getPolyStyle(settings).color,
  54 + stroke: true
  55 + }
  56 + })
  57 + }
  58 + ],
  59 + interactive: false,
  60 + } as PolylineDecoratorOptions
  61 + }
  62 +
  63 + updatePolyline(settings, data, dataSources) {
  64 + this.leafletPoly.setStyle(this.getPolyStyle(settings));
  65 + // this.setPolylineLatLngs(data);
  66 + if(this.polylineDecorator)
  67 + this.polylineDecorator.setPaths(this.leafletPoly);
  68 + }
  69 +
  70 + getPolyStyle(settings: PolylineSettings): L.PolylineOptions {
  71 + return {
  72 + color: settings.useColorFunction ?
  73 + safeExecute(settings.colorFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.color,
  74 + opacity: settings.useStrokeOpacityFunction ?
  75 + safeExecute(settings.strokeOpacityFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.strokeOpacity,
  76 + weight: settings.useStrokeWeightFunction ?
  77 + safeExecute(settings.strokeWeightFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.strokeWeight,
  78 + }
  79 + }
  80 +
  81 + removePolyline() {
  82 + this.map.removeLayer(this.leafletPoly);
  83 + }
  84 +
  85 + getPolylineLatLngs() {
  86 + return this.leafletPoly.getLatLngs();
  87 + }
  88 +
  89 + setPolylineLatLngs(latLngs) {
  90 + this.leafletPoly.setLatLngs(latLngs);
  91 + }
  92 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +
  18 +import L from 'leaflet';
  19 +import LeafletMap from '../leaflet-map';
  20 +import { MapSettings, UnitedMapSettings } from '../map-models';
  21 +import 'leaflet.gridlayer.googlemutant';
  22 +
  23 +let googleLoaded = false;
  24 +
  25 +
  26 +export class GoogleMap extends LeafletMap {
  27 + constructor($container, options: UnitedMapSettings) {
  28 +
  29 + super($container, options);
  30 + this.loadGoogle(() => {
  31 + const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
  32 + const roads = (L.gridLayer as any).googleMutant({
  33 + type: options?.gmDefaultMapType || 'roadmap'
  34 + }).addTo(map);
  35 + super.setMap(map);
  36 + }, options.credentials.apiKey);
  37 + super.initSettings(options);
  38 + }
  39 +
  40 + private loadGoogle(callback, apiKey = 'AIzaSyDoEx2kaGz3PxwbI9T7ccTSg5xjdw8Nw8Q') {
  41 + if (googleLoaded) {
  42 + callback()
  43 + }
  44 + else {
  45 + googleLoaded = true;
  46 + const script = document.createElement('script');
  47 + script.onload = () => {
  48 + callback();
  49 + }
  50 + script.onerror = () => {
  51 + googleLoaded = false;
  52 + }
  53 + script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}`;
  54 + document.getElementsByTagName('head')[0].appendChild(script);
  55 + }
  56 + }
  57 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +import LeafletMap from '../leaflet-map';
  19 +import { MapSettings, UnitedMapSettings } from '../map-models';
  20 +
  21 +export class HEREMap extends LeafletMap {
  22 + constructor($container, options: UnitedMapSettings) {
  23 + const defaultCredentials =
  24 + {
  25 + app_id: 'AhM6TzD9ThyK78CT3ptx',
  26 + app_code: 'p6NPiITB3Vv0GMUFnkLOOg'
  27 + }
  28 + super($container, options);
  29 + const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
  30 + const tileLayer = (L.tileLayer as any).provider(options.mapProvider || 'HERE.normalDay', options.credentials || defaultCredentials);
  31 + tileLayer.addTo(map);
  32 + super.setMap(map);
  33 + super.initSettings(options);
  34 + }
  35 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +import LeafletMap from '../leaflet-map';
  19 +import { MapSettings, UnitedMapSettings } from '../map-models';
  20 +import { aspectCache } from '@app/core/utils';
  21 +
  22 +const maxZoom = 4;// ?
  23 +
  24 +export class ImageMap extends LeafletMap {
  25 +
  26 + imageOverlay;
  27 + aspect = 0;
  28 + width = 0;
  29 + height = 0;
  30 +
  31 + constructor($container: HTMLElement, options: UnitedMapSettings) {
  32 + super($container, options);
  33 + aspectCache(options.mapUrl).subscribe(aspect => {
  34 + this.aspect = aspect;
  35 + this.onResize();
  36 + super.setMap(this.map);
  37 + super.initSettings(options);
  38 + });
  39 + }
  40 +
  41 + updateBounds(updateImage?, lastCenterPos?) {
  42 + const w = this.width;
  43 + const h = this.height;
  44 + let southWest = this.pointToLatLng(0, h);
  45 + let northEast = this.pointToLatLng(w, 0);
  46 + const bounds = new L.LatLngBounds(southWest, northEast);
  47 +
  48 + if (updateImage && this.imageOverlay) {
  49 + this.imageOverlay.remove();
  50 + this.imageOverlay = null;
  51 + }
  52 +
  53 + if (this.imageOverlay) {
  54 + this.imageOverlay.setBounds(bounds);
  55 + } else {
  56 + this.imageOverlay = L.imageOverlay(this.options.mapUrl, bounds).addTo(this.map);
  57 +
  58 + }
  59 + const padding = 200 * maxZoom;
  60 + southWest = this.pointToLatLng(-padding, h + padding);
  61 + northEast = this.pointToLatLng(w + padding, -padding);
  62 + const maxBounds = new L.LatLngBounds(southWest, northEast);
  63 + this.map.setMaxBounds(maxBounds);
  64 + if (lastCenterPos) {
  65 + lastCenterPos.x *= w;
  66 + lastCenterPos.y *= h;
  67 + /* this.ctx.$scope.$injector.get('$mdUtil').nextTick(() => {
  68 + this.map.panTo(center, { animate: false });
  69 + });*/
  70 + }
  71 + }
  72 +
  73 + onResize(updateImage?) {
  74 + let width = this.$container.clientWidth;
  75 + if (width > 0 && this.aspect) {
  76 + let height = width / this.aspect;
  77 + const imageMapHeight = this.$container.clientHeight;
  78 + if (imageMapHeight > 0 && height > imageMapHeight) {
  79 + height = imageMapHeight;
  80 + width = height * this.aspect;
  81 + }
  82 + width *= maxZoom;
  83 + const prevWidth = this.width;
  84 + const prevHeight = this.height;
  85 + if (this.width !== width) {
  86 + this.width = width;
  87 + this.height = width / this.aspect;
  88 + if (!this.map) {
  89 + this.initMap(updateImage);
  90 + } else {
  91 + const lastCenterPos = this.latLngToPoint(this.map.getCenter());
  92 + lastCenterPos.x /= prevWidth;
  93 + lastCenterPos.y /= prevHeight;
  94 + this.updateBounds(updateImage, lastCenterPos);
  95 + this.map.invalidateSize(true);
  96 + // this.updateMarkers();
  97 + }
  98 +
  99 + }
  100 + }
  101 + }
  102 +
  103 + initMap(updateImage?) {
  104 + if (!this.map && this.aspect > 0) {
  105 + const center = this.pointToLatLng(this.width / 2, this.height / 2);
  106 + this.map = L.map(this.$container, {
  107 + minZoom: 1,
  108 + maxZoom,
  109 + scrollWheelZoom: !this.options.disableScrollZooming,
  110 + center,
  111 + zoom: 1,
  112 + crs: L.CRS.Simple,
  113 + attributionControl: false
  114 + });
  115 + this.updateBounds(updateImage);
  116 + // this.updateMarkers();
  117 + }
  118 + }
  119 +
  120 + convertPosition(expression): L.LatLng {
  121 + return this.pointToLatLng(
  122 + expression[this.options.xPosKeyName] * this.width,
  123 + expression[this.options.yPosKeyName] * this.height);
  124 + }
  125 +
  126 + pointToLatLng(x, y): L.LatLng {
  127 + return L.CRS.Simple.pointToLatLng({ x, y } as L.PointExpression, maxZoom - 1);
  128 + }
  129 +
  130 + latLngToPoint(latLng) {
  131 + return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
  132 + }
  133 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +export * from './tencent-map';
  18 +export * from './google-map';
  19 +export * from './here-map';
  20 +export * from './image-map';
  21 +export * from './openstreet-map';
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +import LeafletMap from '../leaflet-map';
  19 +import { MapSettings, UnitedMapSettings } from '../map-models';
  20 +
  21 +export class OpenStreetMap extends LeafletMap {
  22 + constructor($container, options: UnitedMapSettings) {
  23 + super($container, options);
  24 + const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
  25 + const tileLayer = (L.tileLayer as any).provider('OpenStreetMap.Mapnik');
  26 + tileLayer.addTo(map);
  27 + super.setMap(map);
  28 + super.initSettings(options);
  29 + }
  30 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +
  18 +import L from 'leaflet';
  19 +import LeafletMap from '../leaflet-map';
  20 +import { MapSettings, UnitedMapSettings } from '../map-models';
  21 +
  22 +export class TencentMap extends LeafletMap {
  23 + constructor($container, options: UnitedMapSettings) {
  24 + super($container, options);
  25 + const txUrl = 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0';
  26 + const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
  27 + const txLayer = L.tileLayer(txUrl, { subdomains: '0123', tms: true }).addTo(map);
  28 + txLayer.addTo(map);
  29 + super.setMap(map);
  30 + super.initSettings(options);
  31 + }
  32 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +export const googleMapSettingsSchema =
  18 +{
  19 + schema: {
  20 + title: 'Google Map Configuration',
  21 + type: 'object',
  22 + properties: {
  23 + gmApiKey: {
  24 + title: 'Google Maps API Key',
  25 + type: 'string'
  26 + },
  27 + gmDefaultMapType: {
  28 + title: 'Default map type',
  29 + type: 'string',
  30 + default: 'roadmap'
  31 + }
  32 + },
  33 + required: [
  34 + ]
  35 + },
  36 + form: [
  37 + 'gmApiKey',
  38 + {
  39 + key: 'gmDefaultMapType',
  40 + type: 'rc-select',
  41 + multiple: false,
  42 + items: [
  43 + {
  44 + value: 'roadmap',
  45 + label: 'Roadmap'
  46 + },
  47 + {
  48 + value: 'satellite',
  49 + label: 'Satellite'
  50 + },
  51 + {
  52 + value: 'hybrid',
  53 + label: 'Hybrid'
  54 + },
  55 + {
  56 + value: 'terrain',
  57 + label: 'Terrain'
  58 + }
  59 + ]
  60 + }
  61 + ]
  62 +};
  63 +
  64 +export const tencentMapSettingsSchema =
  65 +{
  66 + schema: {
  67 + title: 'Tencent Map Configuration',
  68 + type: 'object',
  69 + properties: {
  70 + tmApiKey: {
  71 + title: 'Tencent Maps API Key',
  72 + type: 'string'
  73 + },
  74 + tmDefaultMapType: {
  75 + title: 'Default map type',
  76 + type: 'string',
  77 + default: 'roadmap'
  78 + }
  79 + },
  80 + required: [
  81 + ]
  82 + },
  83 + form: [
  84 + 'tmApiKey',
  85 + {
  86 + key: 'tmDefaultMapType',
  87 + type: 'rc-select',
  88 + multiple: false,
  89 + items: [
  90 + {
  91 + value: 'roadmap',
  92 + label: 'Roadmap'
  93 + },
  94 + {
  95 + value: 'satellite',
  96 + label: 'Satellite'
  97 + },
  98 + {
  99 + value: 'hybrid',
  100 + label: 'Hybrid'
  101 + },
  102 + ]
  103 + }
  104 + ]
  105 +};
  106 +
  107 +export const hereMapSettingsSchema =
  108 +{
  109 + schema: {
  110 + title: 'HERE Map Configuration',
  111 + type: 'object',
  112 + properties: {
  113 + mapProvider: {
  114 + title: 'Map layer',
  115 + type: 'string',
  116 + default: 'HERE.normalDay'
  117 + },
  118 + credentials: {
  119 + type: 'object',
  120 + properties: {
  121 + app_id: {
  122 + title: 'HERE app id',
  123 + type: 'string'
  124 + },
  125 + app_code: {
  126 + title: 'HERE app code',
  127 + type: 'string'
  128 + }
  129 + },
  130 + required: ['app_id', 'app_code']
  131 + }
  132 + },
  133 + required: []
  134 + },
  135 + form: [
  136 + {
  137 + key: 'mapProvider',
  138 + type: 'rc-select',
  139 + multiple: false,
  140 + items: [
  141 + {
  142 + value: 'HERE.normalDay',
  143 + label: 'HERE.normalDay (Default)'
  144 + },
  145 + {
  146 + value: 'HERE.normalNight',
  147 + label: 'HERE.normalNight'
  148 + },
  149 + {
  150 + value: 'HERE.hybridDay',
  151 + label: 'HERE.hybridDay'
  152 + },
  153 + {
  154 + value: 'HERE.terrainDay',
  155 + label: 'HERE.terrainDay'
  156 + }
  157 + ]
  158 + },
  159 + 'credentials'
  160 + ]
  161 +};
  162 +
  163 +export const openstreetMapSettingsSchema =
  164 +{
  165 + schema: {
  166 + title: 'Openstreet Map Configuration',
  167 + type: 'object',
  168 + properties: {
  169 + mapProvider: {
  170 + title: 'Map provider',
  171 + type: 'string',
  172 + default: 'OpenStreetMap.Mapnik'
  173 + },
  174 + useCustomProvider: {
  175 + title: 'Use custom provider',
  176 + type: 'boolean',
  177 + default: false
  178 + },
  179 + customProviderTileUrl: {
  180 + title: 'Custom provider tile URL',
  181 + type: 'string',
  182 + default: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
  183 + }
  184 + },
  185 + required: []
  186 + },
  187 + form: [
  188 + {
  189 + key: 'mapProvider',
  190 + type: 'rc-select',
  191 + multiple: false,
  192 + items: [
  193 + {
  194 + value: 'OpenStreetMap.Mapnik',
  195 + label: 'OpenStreetMap.Mapnik (Default)'
  196 + },
  197 + {
  198 + value: 'OpenStreetMap.BlackAndWhite',
  199 + label: 'OpenStreetMap.BlackAndWhite'
  200 + },
  201 + {
  202 + value: 'OpenStreetMap.HOT',
  203 + label: 'OpenStreetMap.HOT'
  204 + },
  205 + {
  206 + value: 'Esri.WorldStreetMap',
  207 + label: 'Esri.WorldStreetMap'
  208 + },
  209 + {
  210 + value: 'Esri.WorldTopoMap',
  211 + label: 'Esri.WorldTopoMap'
  212 + },
  213 + {
  214 + value: 'CartoDB.Positron',
  215 + label: 'CartoDB.Positron'
  216 + },
  217 + {
  218 + value: 'CartoDB.DarkMatter',
  219 + label: 'CartoDB.DarkMatter'
  220 + }
  221 + ]
  222 + },
  223 + 'useCustomProvider',
  224 + {
  225 + key: 'customProviderTileUrl',
  226 + condition: 'model.useCustomProvider === true',
  227 + }
  228 + ]
  229 +};
  230 +
  231 +export const commonMapSettingsSchema =
  232 +{
  233 + schema: {
  234 + title: 'Map Configuration',
  235 + type: 'object',
  236 + properties: {
  237 + defaultZoomLevel: {
  238 + title: 'Default map zoom level (0 - 20)',
  239 + type: 'number'
  240 + },
  241 + useDefaultCenterPosition: {
  242 + title: 'Use default map center position',
  243 + type: 'boolean',
  244 + default: false
  245 + },
  246 + defaultCenterPosition: {
  247 + title: 'Default map center position (0,0)',
  248 + type: 'string',
  249 + default: '0,0'
  250 + },
  251 + fitMapBounds: {
  252 + title: 'Fit map bounds to cover all markers',
  253 + type: 'boolean',
  254 + default: true
  255 + },
  256 + disableScrollZooming: {
  257 + title: 'Disable scroll zooming',
  258 + type: 'boolean',
  259 + default: false
  260 + },
  261 + latKeyName: {
  262 + title: 'Latitude key name',
  263 + type: 'string',
  264 + default: 'latitude'
  265 + },
  266 + lngKeyName: {
  267 + title: 'Longitude key name',
  268 + type: 'string',
  269 + default: 'longitude'
  270 + },
  271 + showLabel: {
  272 + title: 'Show label',
  273 + type: 'boolean',
  274 + default: true
  275 + },
  276 + label: {
  277 + title: 'Label (pattern examples: \'${entityName}\', \'${entityName}: (Text ${keyName} units.)\' )',
  278 + type: 'string',
  279 + default: '${entityName}'
  280 + },
  281 + useLabelFunction: {
  282 + title: 'Use label function',
  283 + type: 'boolean',
  284 + default: false
  285 + },
  286 + labelFunction: {
  287 + title: 'Label function: f(data, dsData, dsIndex)',
  288 + type: 'string'
  289 + },
  290 + showTooltip: {
  291 + title: 'Show tooltip',
  292 + type: 'boolean',
  293 + default: true
  294 + },
  295 + showTooltipAction: {
  296 + title: 'Action for displaying the tooltip',
  297 + type: 'string',
  298 + default: 'click'
  299 + },
  300 + autocloseTooltip: {
  301 + title: 'Auto-close tooltips',
  302 + type: 'boolean',
  303 + default: true
  304 + },
  305 + tooltipPattern: {
  306 + title: 'Tooltip (for ex. \'Text ${keyName} units.\' or <link-act name=\'my-action\'>Link text</link-act>\')',
  307 + type: 'string',
  308 + default: '<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}'
  309 + },
  310 + useTooltipFunction: {
  311 + title: 'Use tooltip function',
  312 + type: 'boolean',
  313 + default: false
  314 + },
  315 + tooltipFunction: {
  316 + title: 'Tooltip function: f(data, dsData, dsIndex)',
  317 + type: 'string'
  318 + },
  319 + color: {
  320 + title: 'Color',
  321 + type: 'string'
  322 + },
  323 + useColorFunction: {
  324 + title: 'Use color function',
  325 + type: 'boolean',
  326 + default: false
  327 + },
  328 + colorFunction: {
  329 + title: 'Color function: f(data, dsData, dsIndex)',
  330 + type: 'string'
  331 + },
  332 + showPolygon: {
  333 + title: 'Show polygon',
  334 + type: 'boolean',
  335 + default: false
  336 + },
  337 + polygonKeyName: {
  338 + title: 'Polygon key name',
  339 + type: 'string',
  340 + default: 'coordinates'
  341 + },
  342 + polygonColor: {
  343 + title: 'Polygon color',
  344 + type: 'string'
  345 + },
  346 + polygonOpacity: {
  347 + title: 'Polygon opacity',
  348 + type: 'number',
  349 + default: 0.5
  350 + },
  351 + polygonStrokeColor: {
  352 + title: 'Stroke color',
  353 + type: 'string'
  354 + },
  355 + polygonStrokeOpacity: {
  356 + title: 'Stroke opacity',
  357 + type: 'number',
  358 + default: 1
  359 + },
  360 + polygonStrokeWeight: {
  361 + title: 'Stroke weight',
  362 + type: 'number',
  363 + default: 1
  364 + },
  365 + usePolygonColorFunction: {
  366 + title: 'Use polygon color function',
  367 + type: 'boolean',
  368 + default: false
  369 + },
  370 + polygonColorFunction: {
  371 + title: 'Polygon Color function: f(data, dsData, dsIndex)',
  372 + type: 'string'
  373 + },
  374 + draggableMarker: {
  375 + title: 'Draggable Marker',
  376 + type: 'boolean',
  377 + default: false
  378 + },
  379 + markerImage: {
  380 + title: 'Custom marker image',
  381 + type: 'string'
  382 + },
  383 + markerImageSize: {
  384 + title: 'Custom marker image size (px)',
  385 + type: 'number',
  386 + default: 34
  387 + },
  388 + useMarkerImageFunction: {
  389 + title: 'Use marker image function',
  390 + type: 'boolean',
  391 + default: false
  392 + },
  393 + markerImageFunction: {
  394 + title: 'Marker image function: f(data, images, dsData, dsIndex)',
  395 + type: 'string'
  396 + },
  397 + markerImages: {
  398 + title: 'Marker images',
  399 + type: 'array',
  400 + items: {
  401 + title: 'Marker image',
  402 + type: 'string'
  403 + }
  404 + }
  405 + },
  406 + required: []
  407 + },
  408 + form: [
  409 + 'defaultZoomLevel',
  410 + 'useDefaultCenterPosition',
  411 + 'defaultCenterPosition',
  412 + 'fitMapBounds',
  413 + 'disableScrollZooming',
  414 + 'latKeyName',
  415 + 'lngKeyName',
  416 + 'showLabel',
  417 + 'label',
  418 + 'useLabelFunction',
  419 + 'draggableMarker',
  420 + {
  421 + key: 'labelFunction',
  422 + type: 'javascript'
  423 + },
  424 + 'showTooltip',
  425 + {
  426 + key: 'showTooltipAction',
  427 + type: 'rc-select',
  428 + multiple: false,
  429 + items: [
  430 + {
  431 + value: 'click',
  432 + label: 'Show tooltip on click (Default)'
  433 + },
  434 + {
  435 + value: 'hover',
  436 + label: 'Show tooltip on hover'
  437 + }
  438 + ]
  439 + },
  440 + 'autocloseTooltip',
  441 + {
  442 + key: 'tooltipPattern',
  443 + type: 'textarea'
  444 + },
  445 + 'useTooltipFunction',
  446 + {
  447 + key: 'tooltipFunction',
  448 + type: 'javascript'
  449 + },
  450 + {
  451 + key: 'color',
  452 + type: 'color'
  453 + },
  454 + 'useColorFunction',
  455 + {
  456 + key: 'colorFunction',
  457 + type: 'javascript'
  458 + }, 'showPolygon', 'polygonKeyName',
  459 + {
  460 + key: 'polygonColor',
  461 + type: 'color'
  462 + },
  463 + 'polygonOpacity',
  464 + {
  465 + key: 'polygonStrokeColor',
  466 + type: 'color'
  467 + },
  468 + 'polygonStrokeOpacity', 'polygonStrokeWeight', 'usePolygonColorFunction',
  469 + {
  470 + key: 'polygonColorFunction',
  471 + type: 'javascript'
  472 + },
  473 + {
  474 + key: 'markerImage',
  475 + type: 'image'
  476 + },
  477 + 'markerImageSize',
  478 + 'useMarkerImageFunction',
  479 + {
  480 + key: 'markerImageFunction',
  481 + type: 'javascript'
  482 + },
  483 + {
  484 + key: 'markerImages',
  485 + items: [
  486 + {
  487 + key: 'markerImages[]',
  488 + type: 'image'
  489 + }
  490 + ]
  491 + }
  492 + ]
  493 +};
  494 +
  495 +export const routeMapSettingsSchema =
  496 +{
  497 + schema: {
  498 + title: 'Route Map Configuration',
  499 + type: 'object',
  500 + properties: {
  501 + strokeWeight: {
  502 + title: 'Stroke weight',
  503 + type: 'number',
  504 + default: 2
  505 + },
  506 + strokeOpacity: {
  507 + title: 'Stroke opacity',
  508 + type: 'number',
  509 + default: 1.0
  510 + }
  511 + },
  512 + required: []
  513 + },
  514 + form: [
  515 + 'strokeWeight',
  516 + 'strokeOpacity'
  517 + ]
  518 +};
  519 +
  520 +export const markerClusteringSettingsSchema =
  521 +{
  522 + schema: {
  523 + title: 'Markers Clustering Configuration',
  524 + type: 'object',
  525 + properties: {
  526 + useClusterMarkers: {
  527 + title: 'Use map markers clustering',
  528 + type: 'boolean',
  529 + default: false
  530 + },
  531 + zoomOnClick: {
  532 + title: 'Zoom when clicking on a cluster',
  533 + type: 'boolean',
  534 + default: true
  535 + },
  536 + maxZoom: {
  537 + title: 'The maximum zoom level when a marker can be part of a cluster (0 - 18)',
  538 + type: 'number'
  539 + }
  540 + },
  541 + required: []
  542 + },
  543 + form: [
  544 + 'useClusterMarkers',
  545 + 'zoomOnClick',
  546 + 'maxZoom'
  547 + ]
  548 +};
  549 +
  550 +export const markerClusteringSettingsSchemaGoogle =
  551 +{
  552 + schema: {
  553 + title: 'Marker Clustering Configuration Google',
  554 + type: 'object',
  555 + properties: {
  556 + gridSize: {
  557 + title: 'Maximum radius that a cluster will cover in pixels',
  558 + type: 'number',
  559 + default: 60
  560 + },
  561 + minimumClusterSize: {
  562 + title: 'The minimum number of markers in a cluster',
  563 + type: 'number'
  564 + }
  565 + },
  566 + required: []
  567 + },
  568 + form: [
  569 + 'gridSize',
  570 + 'minimumClusterSize'
  571 + ]
  572 +};
  573 +
  574 +export const markerClusteringSettingsSchemaLeaflet =
  575 +{
  576 + schema: {
  577 + title: 'Markers Clustering Configuration Leaflet',
  578 + type: 'object',
  579 + properties: {
  580 + showCoverageOnHover: {
  581 + title: 'Show the bounds of markers when mouse over a cluster',
  582 + type: 'boolean',
  583 + default: true
  584 + },
  585 + animate: {
  586 + title: 'Show animation on markers when zooming',
  587 + type: 'boolean',
  588 + default: true
  589 + },
  590 + maxClusterRadius: {
  591 + title: 'Maximum radius that a cluster will cover in pixels',
  592 + type: 'number',
  593 + default: 80
  594 + },
  595 + chunkedLoading: {
  596 + title: 'Use chunks for adding markers so that the page does not freeze',
  597 + type: 'boolean',
  598 + default: false
  599 + },
  600 + removeOutsideVisibleBounds: {
  601 + title: 'Use lazy load for adding markers',
  602 + type: 'boolean',
  603 + default: true
  604 + }
  605 + },
  606 + required: []
  607 + },
  608 + form: [
  609 + 'showCoverageOnHover',
  610 + 'animate',
  611 + 'maxClusterRadius',
  612 + 'chunkedLoading',
  613 + 'removeOutsideVisibleBounds'
  614 + ]
  615 +};
  616 +
  617 +export const imageMapSettingsSchema =
  618 +{
  619 + schema: {
  620 + title: 'Image Map Configuration',
  621 + type: 'object',
  622 + properties: {
  623 + mapImageUrl: {
  624 + title: 'Image map background',
  625 + type: 'string',
  626 + default: 'data:image/svg+xml;base64,PHN2ZyBpZD0ic3ZnMiIgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMTAwIiB3aWR0aD0iMTAwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDEwMCAxMDAiPgogPGcgaWQ9ImxheWVyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAtOTUyLjM2KSI+CiAgPHJlY3QgaWQ9InJlY3Q0Njg0IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBoZWlnaHQ9Ijk5LjAxIiB3aWR0aD0iOTkuMDEiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiB5PSI5NTIuODYiIHg9Ii40OTUwNSIgc3Ryb2tlLXdpZHRoPSIuOTkwMTAiIGZpbGw9IiNlZWUiLz4KICA8dGV4dCBpZD0idGV4dDQ2ODYiIHN0eWxlPSJ3b3JkLXNwYWNpbmc6MHB4O2xldHRlci1zcGFjaW5nOjBweDt0ZXh0LWFuY2hvcjptaWRkbGU7dGV4dC1hbGlnbjpjZW50ZXIiIGZvbnQtd2VpZ2h0PSJib2xkIiB4bWw6c3BhY2U9InByZXNlcnZlIiBmb250LXNpemU9IjEwcHgiIGxpbmUtaGVpZ2h0PSIxMjUlIiB5PSI5NzAuNzI4MDkiIHg9IjQ5LjM5NjQ3NyIgZm9udC1mYW1pbHk9IlJvYm90byIgZmlsbD0iIzY2NjY2NiI+PHRzcGFuIGlkPSJ0c3BhbjQ2OTAiIHg9IjUwLjY0NjQ3NyIgeT0iOTcwLjcyODA5Ij5JbWFnZSBiYWNrZ3JvdW5kIDwvdHNwYW4+PHRzcGFuIGlkPSJ0c3BhbjQ2OTIiIHg9IjQ5LjM5NjQ3NyIgeT0iOTgzLjIyODA5Ij5pcyBub3QgY29uZmlndXJlZDwvdHNwYW4+PC90ZXh0PgogIDxyZWN0IGlkPSJyZWN0NDY5NCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgaGVpZ2h0PSIxOS4zNiIgd2lkdGg9IjY5LjM2IiBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgeT0iOTkyLjY4IiB4PSIxNS4zMiIgc3Ryb2tlLXdpZHRoPSIuNjM5ODYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+Cg=='
  627 + },
  628 + imageEntityAlias: {
  629 + title: 'Image URL source entity alias',
  630 + type: 'string',
  631 + default: ''
  632 + },
  633 + imageUrlAttribute: {
  634 + title: 'Image URL source entity attribute',
  635 + type: 'string',
  636 + default: ''
  637 + },
  638 + disableScrollZooming: {
  639 + title: 'Disable scroll zooming',
  640 + type: 'boolean',
  641 + default: false
  642 + },
  643 + xPosKeyName: {
  644 + title: 'X position key name',
  645 + type: 'string',
  646 + default: 'xPos'
  647 + },
  648 + yPosKeyName: {
  649 + title: 'Y position key name',
  650 + type: 'string',
  651 + default: 'yPos'
  652 + },
  653 + showLabel: {
  654 + title: 'Show label',
  655 + type: 'boolean',
  656 + default: true
  657 + },
  658 + label: {
  659 + title: 'Label (pattern examples: \'${entityName}\', \'${entityName}: (Text ${keyName} units.)\' )',
  660 + type: 'string',
  661 + default: '${entityName}'
  662 + },
  663 + useLabelFunction: {
  664 + title: 'Use label function',
  665 + type: 'boolean',
  666 + default: false
  667 + },
  668 + labelFunction: {
  669 + title: 'Label function: f(data, dsData, dsIndex)',
  670 + type: 'string'
  671 + },
  672 + showTooltip: {
  673 + title: 'Show tooltip',
  674 + type: 'boolean',
  675 + default: true
  676 + },
  677 + showTooltipAction: {
  678 + title: 'Action for displaying the tooltip',
  679 + type: 'string',
  680 + default: 'click'
  681 + },
  682 + autocloseTooltip: {
  683 + title: 'Auto-close tooltips',
  684 + type: 'boolean',
  685 + default: true
  686 + },
  687 + tooltipPattern: {
  688 + title: 'Tooltip (for ex. \'Text ${keyName} units.\' or <link-act name=\'my-action\'>Link text</link-act>\')',
  689 + type: 'string',
  690 + default: '<b>${entityName}</b><br/><br/><b>X Pos:</b> ${xPos:2}<br/><b>Y Pos:</b> ${yPos:2}'
  691 + },
  692 + useTooltipFunction: {
  693 + title: 'Use tooltip function',
  694 + type: 'boolean',
  695 + default: false
  696 + },
  697 + tooltipFunction: {
  698 + title: 'Tooltip function: f(data, dsData, dsIndex)',
  699 + type: 'string'
  700 + },
  701 + color: {
  702 + title: 'Color',
  703 + type: 'string'
  704 + },
  705 + posFunction: {
  706 + title: 'Position conversion function: f(origXPos, origYPos), should return x,y coordinates as double from 0 to 1 each',
  707 + type: 'string',
  708 + default: 'return {x: origXPos, y: origYPos};'
  709 + },
  710 + markerOffsetX: {
  711 + title: 'Marker X offset relative to position',
  712 + type: 'number',
  713 + default: 0.5
  714 + },
  715 + markerOffsetY: {
  716 + title: 'Marker Y offset relative to position',
  717 + type: 'number',
  718 + default: 1
  719 + },
  720 + useColorFunction: {
  721 + title: 'Use color function',
  722 + type: 'boolean',
  723 + default: false
  724 + },
  725 + colorFunction: {
  726 + title: 'Color function: f(data, dsData, dsIndex)',
  727 + type: 'string'
  728 + },
  729 + markerImage: {
  730 + title: 'Custom marker image',
  731 + type: 'string'
  732 + },
  733 + markerImageSize: {
  734 + title: 'Custom marker image size (px)',
  735 + type: 'number',
  736 + default: 34
  737 + },
  738 + useMarkerImageFunction: {
  739 + title: 'Use marker image function',
  740 + type: 'boolean',
  741 + default: false
  742 + },
  743 + markerImageFunction: {
  744 + title: 'Marker image function: f(data, images, dsData, dsIndex)',
  745 + type: 'string'
  746 + },
  747 + markerImages: {
  748 + title: 'Marker images',
  749 + type: 'array',
  750 + items: {
  751 + title: 'Marker image',
  752 + type: 'string'
  753 + }
  754 + }
  755 + },
  756 + required: []
  757 + },
  758 + form: [
  759 + {
  760 + key: 'mapImageUrl',
  761 + type: 'image'
  762 + },
  763 + 'imageEntityAlias',
  764 + 'imageUrlAttribute',
  765 + 'disableScrollZooming',
  766 + 'xPosKeyName',
  767 + 'yPosKeyName',
  768 + 'showLabel',
  769 + 'label',
  770 + 'useLabelFunction',
  771 + {
  772 + key: 'labelFunction',
  773 + type: 'javascript'
  774 + },
  775 + 'showTooltip',
  776 + {
  777 + key: 'showTooltipAction',
  778 + type: 'rc-select',
  779 + multiple: false,
  780 + items: [
  781 + {
  782 + value: 'click',
  783 + label: 'Show tooltip on click (Default)'
  784 + },
  785 + {
  786 + value: 'hover',
  787 + label: 'Show tooltip on hover'
  788 + }
  789 + ]
  790 + },
  791 + 'autocloseTooltip',
  792 + {
  793 + key: 'tooltipPattern',
  794 + type: 'textarea'
  795 + },
  796 + 'useTooltipFunction',
  797 + {
  798 + key: 'tooltipFunction',
  799 + type: 'javascript'
  800 + },
  801 + {
  802 + key: 'color',
  803 + type: 'color'
  804 + },
  805 + {
  806 + key: 'posFunction',
  807 + type: 'javascript'
  808 + },
  809 + 'markerOffsetX',
  810 + 'markerOffsetY',
  811 + 'useColorFunction',
  812 + {
  813 + key: 'colorFunction',
  814 + type: 'javascript'
  815 + },
  816 + {
  817 + key: 'markerImage',
  818 + type: 'image'
  819 + },
  820 + 'markerImageSize',
  821 + 'useMarkerImageFunction',
  822 + {
  823 + key: 'markerImageFunction',
  824 + type: 'javascript'
  825 + },
  826 + {
  827 + key: 'markerImages',
  828 + items: [
  829 + {
  830 + key: 'markerImages[]',
  831 + type: 'image'
  832 + }
  833 + ]
  834 + }
  835 + ]
  836 +};
  837 +
  838 +export const mapProviderSchema =
  839 +{
  840 + schema: {
  841 + title: 'Map Provider Configuration',
  842 + type: 'object',
  843 + properties: {
  844 + provider: {
  845 + title: 'Map Provider',
  846 + type: 'string',
  847 + default: 'openstreet-map'
  848 + }
  849 + },
  850 + required: []
  851 + },
  852 + form: [
  853 + {
  854 + key: 'provider',
  855 + type: 'rc-select',
  856 + multiple: false,
  857 + items: [
  858 + {
  859 + value: 'google-map',
  860 + label: 'Google maps'
  861 + },
  862 + {
  863 + value: 'openstreet-map',
  864 + label: 'Openstreet maps'
  865 + },
  866 + {
  867 + value: 'here',
  868 + label: 'HERE maps'
  869 + },
  870 + {
  871 + value: 'image-map',
  872 + label: 'Image map'
  873 + },
  874 + {
  875 + value: 'tencent-map',
  876 + label: 'Tencent maps'
  877 + }
  878 + ]
  879 + }
  880 + ]
  881 +};
  882 +
  883 +
  884 +export const tripAnimationSchema = {
  885 + schema: {
  886 + title: 'Openstreet Map Configuration',
  887 + type: 'object',
  888 + properties: {
  889 + normalizationStep: {
  890 + title: 'Normalization data step (ms)',
  891 + type: 'number',
  892 + default: 1000
  893 + },
  894 + latKeyName: {
  895 + title: 'Latitude key name',
  896 + type: 'string',
  897 + default: 'latitude'
  898 + },
  899 + lngKeyName: {
  900 + title: 'Longitude key name',
  901 + type: 'string',
  902 + default: 'longitude'
  903 + },
  904 + polKeyName: {
  905 + title: 'Polygon key name',
  906 + type: 'string',
  907 + default: 'coordinates'
  908 + },
  909 + showLabel: {
  910 + title: 'Show label',
  911 + type: 'boolean',
  912 + default: true
  913 + },
  914 + label: {
  915 + title: 'Label (pattern examples: \'${entityName}\', \'${entityName}: (Text ${keyName} units.)\' )',
  916 + type: 'string',
  917 + default: '${entityName}'
  918 + },
  919 + useLabelFunction: {
  920 + title: 'Use label function',
  921 + type: 'boolean',
  922 + default: false
  923 + },
  924 + labelFunction: {
  925 + title: 'Label function: f(data, dsData, dsIndex)',
  926 + type: 'string'
  927 + },
  928 + showTooltip: {
  929 + title: 'Show tooltip',
  930 + type: 'boolean',
  931 + default: true
  932 + },
  933 + tooltipColor: {
  934 + title: 'Tooltip background color',
  935 + type: 'string',
  936 + default: '#fff'
  937 + },
  938 + tooltipFontColor: {
  939 + title: 'Tooltip font color',
  940 + type: 'string',
  941 + default: '#000'
  942 + },
  943 + tooltipOpacity: {
  944 + title: 'Tooltip opacity (0-1)',
  945 + type: 'number',
  946 + default: 1
  947 + },
  948 + tooltipPattern: {
  949 + title: 'Tooltip (for ex. \'Text ${keyName} units.\' or <link-act name=\'my-action\'>Link text</link-act>\')',
  950 + type: 'string',
  951 + default: '<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}'
  952 + },
  953 + useTooltipFunction: {
  954 + title: 'Use tooltip function',
  955 + type: 'boolean',
  956 + default: false
  957 + },
  958 + tooltipFunction: {
  959 + title: 'Tooltip function: f(data, dsData, dsIndex)',
  960 + type: 'string'
  961 + },
  962 + color: {
  963 + title: 'Path color',
  964 + type: 'string'
  965 + },
  966 + strokeWeight: {
  967 + title: 'Stroke weight',
  968 + type: 'number',
  969 + default: 2
  970 + },
  971 + strokeOpacity: {
  972 + title: 'Stroke opacity',
  973 + type: 'number',
  974 + default: 1
  975 + },
  976 + useColorFunction: {
  977 + title: 'Use path color function',
  978 + type: 'boolean',
  979 + default: false
  980 + },
  981 + colorFunction: {
  982 + title: 'Path color function: f(data, dsData, dsIndex)',
  983 + type: 'string'
  984 + },
  985 + usePolylineDecorator: {
  986 + title: 'Use path decorator',
  987 + type: 'boolean',
  988 + default: false
  989 + },
  990 + decoratorSymbol: {
  991 + title: 'Decorator symbol',
  992 + type: 'string',
  993 + default: 'arrowHead'
  994 + },
  995 + decoratorSymbolSize: {
  996 + title: 'Decorator symbol size (px)',
  997 + type: 'number',
  998 + default: 10
  999 + },
  1000 + useDecoratorCustomColor: {
  1001 + title: 'Use path decorator custom color',
  1002 + type: 'boolean',
  1003 + default: false
  1004 + },
  1005 + decoratorCustomColor: {
  1006 + title: 'Decorator custom color',
  1007 + type: 'string',
  1008 + default: '#000'
  1009 + },
  1010 + decoratorOffset: {
  1011 + title: 'Decorator offset',
  1012 + type: 'string',
  1013 + default: '20px'
  1014 + },
  1015 + endDecoratorOffset: {
  1016 + title: 'End decorator offset',
  1017 + type: 'string',
  1018 + default: '20px'
  1019 + },
  1020 + decoratorRepeat: {
  1021 + title: 'Decorator repeat',
  1022 + type: 'string',
  1023 + default: '20px'
  1024 + },
  1025 + showPolygon: {
  1026 + title: 'Show polygon',
  1027 + type: 'boolean',
  1028 + default: false
  1029 + },
  1030 + polygonTooltipPattern: {
  1031 + title: 'Tooltip (for ex. \'Text ${keyName} units.\' or <link-act name=\'my-action\'>Link text</link-act>\')',
  1032 + type: 'string',
  1033 + default: '<b>${entityName}</b><br/><br/><b>TimeStamp:</b> ${ts:7}'
  1034 + },
  1035 + usePolygonTooltipFunction: {
  1036 + title: 'Use polygon tooltip function',
  1037 + type: 'boolean',
  1038 + default: false
  1039 + },
  1040 + polygonTooltipFunction: {
  1041 + title: 'Polygon tooltip function: f(data, dsData, dsIndex)',
  1042 + type: 'string'
  1043 + },
  1044 + polygonColor: {
  1045 + title: 'Polygon color',
  1046 + type: 'string'
  1047 + },
  1048 + polygonOpacity: {
  1049 + title: 'Polygon opacity',
  1050 + type: 'number',
  1051 + default: 0.5
  1052 + },
  1053 + polygonStrokeColor: {
  1054 + title: 'Polygon border color',
  1055 + type: 'string'
  1056 + },
  1057 + polygonStrokeOpacity: {
  1058 + title: 'Polygon border opacity',
  1059 + type: 'number',
  1060 + default: 1
  1061 + },
  1062 + polygonStrokeWeight: {
  1063 + title: 'Polygon border weight',
  1064 + type: 'number',
  1065 + default: 1
  1066 + },
  1067 + usePolygonColorFunction: {
  1068 + title: 'Use polygon color function',
  1069 + type: 'boolean',
  1070 + default: false
  1071 + },
  1072 + polygonColorFunction: {
  1073 + title: 'Polygon Color function: f(data, dsData, dsIndex)',
  1074 + type: 'string'
  1075 + },
  1076 + showPoints: {
  1077 + title: 'Show points',
  1078 + type: 'boolean',
  1079 + default: false
  1080 + },
  1081 + pointColor: {
  1082 + title: 'Point color',
  1083 + type: 'string'
  1084 + },
  1085 + pointSize: {
  1086 + title: 'Point size (px)',
  1087 + type: 'number',
  1088 + default: 10
  1089 + },
  1090 + usePointAsAnchor: {
  1091 + title: 'Use point as anchor',
  1092 + type: 'boolean',
  1093 + default: false
  1094 + },
  1095 + pointAsAnchorFunction: {
  1096 + title: 'Point as anchor function: f(data, dsData, dsIndex)',
  1097 + type: 'string'
  1098 + },
  1099 + pointTooltipOnRightPanel: {
  1100 + title: 'Independant point tooltip',
  1101 + type: 'boolean',
  1102 + default: true
  1103 + },
  1104 + autocloseTooltip: {
  1105 + title: 'Auto-close point popup',
  1106 + type: 'boolean',
  1107 + default: true
  1108 + },
  1109 + markerImage: {
  1110 + title: 'Custom marker image',
  1111 + type: 'string'
  1112 + },
  1113 + markerImageSize: {
  1114 + title: 'Custom marker image size (px)',
  1115 + type: 'number',
  1116 + default: 34
  1117 + },
  1118 + rotationAngle: {
  1119 + title: 'Set additional rotation angle for marker (deg)',
  1120 + type: 'number',
  1121 + default: 180
  1122 + },
  1123 + useMarkerImageFunction: {
  1124 + title: 'Use marker image function',
  1125 + type: 'boolean',
  1126 + default: false
  1127 + },
  1128 + markerImageFunction: {
  1129 + title: 'Marker image function: f(data, images, dsData, dsIndex)',
  1130 + type: 'string'
  1131 + },
  1132 + markerImages: {
  1133 + title: 'Marker images',
  1134 + type: 'array',
  1135 + items: {
  1136 + title: 'Marker image',
  1137 + type: 'string'
  1138 + }
  1139 + }
  1140 + },
  1141 + required: []
  1142 + },
  1143 + form: [{
  1144 + key: 'mapProvider',
  1145 + type: 'rc-select',
  1146 + multiple: false,
  1147 + items: [{
  1148 + value: 'OpenStreetMap.Mapnik',
  1149 + label: 'OpenStreetMap.Mapnik (Default)'
  1150 + }, {
  1151 + value: 'OpenStreetMap.BlackAndWhite',
  1152 + label: 'OpenStreetMap.BlackAndWhite'
  1153 + }, {
  1154 + value: 'OpenStreetMap.HOT',
  1155 + label: 'OpenStreetMap.HOT'
  1156 + }, {
  1157 + value: 'Esri.WorldStreetMap',
  1158 + label: 'Esri.WorldStreetMap'
  1159 + }, {
  1160 + value: 'Esri.WorldTopoMap',
  1161 + label: 'Esri.WorldTopoMap'
  1162 + }, {
  1163 + value: 'CartoDB.Positron',
  1164 + label: 'CartoDB.Positron'
  1165 + }, {
  1166 + value: 'CartoDB.DarkMatter',
  1167 + label: 'CartoDB.DarkMatter'
  1168 + }]
  1169 + }, 'normalizationStep', 'latKeyName', 'lngKeyName', 'polKeyName', 'showLabel', 'label', 'useLabelFunction', {
  1170 + key: 'labelFunction',
  1171 + type: 'javascript'
  1172 + }, 'showTooltip', {
  1173 + key: 'tooltipColor',
  1174 + type: 'color'
  1175 + }, {
  1176 + key: 'tooltipFontColor',
  1177 + type: 'color'
  1178 + }, 'tooltipOpacity', {
  1179 + key: 'tooltipPattern',
  1180 + type: 'textarea'
  1181 + }, 'useTooltipFunction', {
  1182 + key: 'tooltipFunction',
  1183 + type: 'javascript'
  1184 + }, {
  1185 + key: 'color',
  1186 + type: 'color'
  1187 + }, 'useColorFunction', {
  1188 + key: 'colorFunction',
  1189 + type: 'javascript'
  1190 + }, 'usePolylineDecorator', {
  1191 + key: 'decoratorSymbol',
  1192 + type: 'rc-select',
  1193 + multiple: false,
  1194 + items: [{
  1195 + value: 'arrowHead',
  1196 + label: 'Arrow'
  1197 + }, {
  1198 + value: 'dash',
  1199 + label: 'Dash'
  1200 + }]
  1201 + }, 'decoratorSymbolSize', 'useDecoratorCustomColor', {
  1202 + key: 'decoratorCustomColor',
  1203 + type: 'color'
  1204 + }, {
  1205 + key: 'decoratorOffset',
  1206 + type: 'textarea'
  1207 + }, {
  1208 + key: 'endDecoratorOffset',
  1209 + type: 'textarea'
  1210 + }, {
  1211 + key: 'decoratorRepeat',
  1212 + type: 'textarea'
  1213 + }, 'strokeWeight', 'strokeOpacity', 'showPolygon', {
  1214 + key: 'polygonTooltipPattern',
  1215 + type: 'textarea'
  1216 + }, 'usePolygonTooltipFunction', {
  1217 + key: 'polygonTooltipFunction',
  1218 + type: 'javascript'
  1219 + }, {
  1220 + key: 'polygonColor',
  1221 + type: 'color'
  1222 + }, 'polygonOpacity', {
  1223 + key: 'polygonStrokeColor',
  1224 + type: 'color'
  1225 + }, 'polygonStrokeOpacity', 'polygonStrokeWeight', 'usePolygonColorFunction', {
  1226 + key: 'polygonColorFunction',
  1227 + type: 'javascript'
  1228 + }, 'showPoints', {
  1229 + key: 'pointColor',
  1230 + type: 'color'
  1231 + }, 'pointSize', 'usePointAsAnchor', {
  1232 + key: 'pointAsAnchorFunction',
  1233 + type: 'javascript'
  1234 + }, 'pointTooltipOnRightPanel', 'autocloseTooltip', {
  1235 + key: 'markerImage',
  1236 + type: 'image'
  1237 + }, 'markerImageSize', 'rotationAngle', 'useMarkerImageFunction',
  1238 + {
  1239 + key: 'markerImageFunction',
  1240 + type: 'javascript'
  1241 + }, {
  1242 + key: 'markerImages',
  1243 + items: [
  1244 + {
  1245 + key: 'markerImages[]',
  1246 + type: 'image'
  1247 + }
  1248 + ]
  1249 + }]
  1250 +}
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div class="trip-animation-widget">
  19 + <div class="trip-animation-label-container" *ngIf="settings.showLabel">
  20 + {{settings.label | tbParseTemplate: activeTrip}}
  21 + </div>
  22 + <div class="trip-animation-container" layout="column">
  23 + <div class="map" #map></div>
  24 + <div class="trip-animation-info-panel" layout="row">
  25 + <button class="tooltip-button" mat-mini-fab color="primary" aria-label="tooltip"
  26 + *ngIf="settings.showTooltip" (click)="showHideTooltip()">
  27 + <mat-icon>info_outline</mat-icon>
  28 + </button>
  29 + </div>
  30 + <div class="trip-animation-tooltip md-whiteframe-z4" layout="column"
  31 + [ngClass]="{'trip-animation-tooltip-hidden':!visibleTooltip}" [innerHTML]="mainTooltip"
  32 + [ngStyle]="{'background-color': settings.tooltipColor, 'opacity': settings.tooltipOpacity, 'color': settings.tooltipFontColor}">
  33 + </div>
  34 + </div>
  35 + <tb-history-selector *ngIf="historicalData" [settings]="settings" [intervals]="intervals"
  36 + (onTimeUpdated)="timeUpdated($event)"></tb-history-selector>
  37 +</div>
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +.trip-animation-widget {
  18 + position: relative;
  19 + width: 100%;
  20 + height: 100%;
  21 + font-size: 16px;
  22 + line-height: 24px;
  23 + display: flex;
  24 + flex-direction: column;
  25 +
  26 + .trip-animation-label-container {
  27 + height: 24px;
  28 + }
  29 +
  30 + .trip-animation-container {
  31 + position: relative;
  32 + z-index: 1;
  33 + flex: 1;
  34 + width: 100%;
  35 +
  36 + .map {
  37 + width: 100%;
  38 + height: 100%;
  39 + }
  40 +
  41 + .trip-animation-info-panel {
  42 + position: absolute;
  43 + top: 0;
  44 + right: 0;
  45 + pointer-events: none;
  46 +
  47 + .tooltip-button {
  48 + top: 0;
  49 + left: 0;
  50 + width: 32px;
  51 + min-width: 32px;
  52 + height: 32px;
  53 + min-height: 32px;
  54 + padding: 0 0 2px;
  55 + margin: 2px;
  56 + line-height: 24px;
  57 + z-index: 999;
  58 +
  59 + &::ng-deep .mat-button-wrapper {
  60 + padding: 0;
  61 + }
  62 +
  63 + mat-icon {
  64 + width: 24px;
  65 + height: 24px;
  66 +
  67 + svg {
  68 + width: inherit;
  69 + height: inherit;
  70 + }
  71 + }
  72 + }
  73 + }
  74 +
  75 + .trip-animation-tooltip {
  76 + position: absolute;
  77 + top: 38px;
  78 + right: 0;
  79 + z-index: 400;
  80 + padding: 10px;
  81 + background-color: #fff;
  82 + transition: 0.3s ease-in-out;
  83 +
  84 + &-hidden {
  85 + transform: translateX(110%);
  86 + }
  87 + }
  88 + }
  89 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import L from 'leaflet';
  18 +import _ from 'lodash';
  19 +import tinycolor from 'tinycolor2';
  20 +import { interpolateOnPointSegment } from 'leaflet-geometryutil';
  21 +
  22 +import { Component, OnInit, Input, ViewChild, AfterViewInit, ChangeDetectorRef, SecurityContext } from '@angular/core';
  23 +import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2';
  24 +import { MapProviders } from '../lib/maps/map-models';
  25 +import { parseArray, parseTemplate, safeExecute } from '@app/core/utils';
  26 +import { initSchema, addToSchema, addGroupInfo } from '@app/core/schema-utils';
  27 +import { tripAnimationSchema } from '../lib/maps/schemes';
  28 +import { DomSanitizer } from '@angular/platform-browser';
  29 +import { WidgetConfig, JsonSchema, JsonSettingsSchema } from '@app/shared/public-api';
  30 +import { WidgetContext } from '@app/modules/home/models/widget-component.models';
  31 +import { getRatio, findAngle } from '../lib/maps/maps-utils';
  32 +
  33 +
  34 +@Component({
  35 + selector: 'trip-animation',
  36 + templateUrl: './trip-animation.component.html',
  37 + styleUrls: ['./trip-animation.component.scss']
  38 +})
  39 +export class TripAnimationComponent implements OnInit, AfterViewInit {
  40 +
  41 + constructor(private cd: ChangeDetectorRef, private sanitizer: DomSanitizer) { }
  42 +
  43 + @Input() ctx: WidgetContext;
  44 +
  45 + @ViewChild('map') mapContainer;
  46 +
  47 + mapWidget: MapWidgetController;
  48 + historicalData;
  49 + intervals;
  50 + normalizationStep = 1000;
  51 + interpolatedData = [];
  52 + widgetConfig: WidgetConfig;
  53 + settings;
  54 + mainTooltip = '';
  55 + visibleTooltip = false;
  56 + activeTrip;
  57 +
  58 + static getSettingsSchema(): JsonSettingsSchema {
  59 + const schema = initSchema();
  60 + addToSchema(schema, TbMapWidgetV2.getProvidersSchema());
  61 + addGroupInfo(schema, 'Map Provider Settings');
  62 + addToSchema(schema, tripAnimationSchema);
  63 + addGroupInfo(schema, 'Trip Animation Settings');
  64 + return schema;
  65 + }
  66 +
  67 + ngOnInit(): void {
  68 + this.widgetConfig = this.ctx.widgetConfig;
  69 + const settings = {
  70 + normalizationStep: 1000,
  71 + showLabel: false,
  72 + buttonColor: tinycolor(this.widgetConfig.color).setAlpha(0.54).toRgbString(),
  73 + disabledButtonColor: tinycolor(this.widgetConfig.color).setAlpha(0.3).toRgbString(),
  74 + rotationAngle: 0
  75 + }
  76 + this.settings = { ...settings, ...this.ctx.settings };
  77 + const subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]];
  78 + if (subscription) subscription.callbacks.onDataUpdated = (updated) => {
  79 + this.historicalData = parseArray(this.ctx.data);
  80 + this.activeTrip = this.historicalData[0][0];
  81 + this.calculateIntervals();
  82 + this.timeUpdated(this.intervals[0]);
  83 + this.mapWidget.map.updatePolylines(this.interpolatedData.map(ds => _.values(ds)));
  84 +
  85 + this.mapWidget.map.map?.invalidateSize();
  86 + this.cd.detectChanges();
  87 + }
  88 + }
  89 +
  90 + ngAfterViewInit() {
  91 + const ctxCopy: WidgetContext = _.cloneDeep(this.ctx);
  92 + ctxCopy.settings.showLabel = false;
  93 + ctxCopy.settings.showTooltip = false;
  94 + this.mapWidget = new MapWidgetController(MapProviders.openstreet, false, ctxCopy, this.mapContainer.nativeElement);
  95 + }
  96 +
  97 + timeUpdated(time: number) {
  98 + const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]);
  99 + this.activeTrip = currentPosition[0];
  100 + if (this.settings.showPolygon) {
  101 + this.mapWidget.map.updatePolygons(this.interpolatedData);
  102 + }
  103 + this.mapWidget.map.updateMarkers(currentPosition);
  104 + }
  105 +
  106 + setActiveTrip() {
  107 +
  108 + }
  109 +
  110 + calculateIntervals() {
  111 + this.historicalData.forEach((dataSource, index) => {
  112 + this.intervals = [];
  113 + for (let time = dataSource[0]?.time; time < dataSource[dataSource.length - 1]?.time; time += this.normalizationStep) {
  114 + this.intervals.push(time);
  115 + }
  116 + this.intervals.push(dataSource[dataSource.length - 1]?.time);
  117 + this.interpolatedData[index] = this.interpolateArray(dataSource, this.intervals);
  118 + });
  119 + }
  120 +
  121 + showHideTooltip() {
  122 + const tooltipText: string = this.settings.useTooltipFunction ?
  123 + safeExecute(this.settings.tooolTipFunction, [this.activeTrip, this.historicalData, 0])
  124 + : this.settings.tooltipPattern;
  125 +
  126 + this.mainTooltip = this.sanitizer.sanitize(SecurityContext.HTML, parseTemplate(tooltipText, this.activeTrip))
  127 + this.visibleTooltip = !this.visibleTooltip;
  128 + }
  129 +
  130 + interpolateArray(originData, interpolatedIntervals) {
  131 +
  132 + const result = {};
  133 +
  134 + for (let i = 1, j = 0; i < originData.length && j < interpolatedIntervals.length;) {
  135 + const currentTime = interpolatedIntervals[j];
  136 + while (originData[i].time < currentTime) i++;
  137 + const before = originData[i - 1];
  138 + const after = originData[i];
  139 + const interpolation = interpolateOnPointSegment(
  140 + new L.Point(before.latitude, before.longitude),
  141 + new L.Point(after.latitude, after.longitude),
  142 + getRatio(before.time, after.time, currentTime));
  143 + result[currentTime] = ({
  144 + ...originData[i],
  145 + rotationAngle: findAngle(before, after) + this.settings.rotationAngle,
  146 + latitude: interpolation.x,
  147 + longitude: interpolation.y
  148 + });
  149 + j++;
  150 + }
  151 + return result;
  152 + }
  153 +}
  154 +
  155 +export let TbTripAnimationWidget = TripAnimationComponent;
  156 +
@@ -31,6 +31,7 @@ import { @@ -31,6 +31,7 @@ import {
31 DateRangeNavigatorWidgetComponent 31 DateRangeNavigatorWidgetComponent
32 } from '@home/components/widget/lib/date-range-navigator/date-range-navigator.component'; 32 } from '@home/components/widget/lib/date-range-navigator/date-range-navigator.component';
33 import { MultipleInputWidgetComponent } from './lib/multiple-input-widget.component'; 33 import { MultipleInputWidgetComponent } from './lib/multiple-input-widget.component';
  34 +import { TripAnimationComponent } from './trip-animation/trip-animation.component';
34 import { WebCameraInputWidgetComponent } from './lib/web-camera-input.component'; 35 import { WebCameraInputWidgetComponent } from './lib/web-camera-input.component';
35 36
36 @NgModule({ 37 @NgModule({
@@ -45,6 +46,7 @@ import { WebCameraInputWidgetComponent } from './lib/web-camera-input.component' @@ -45,6 +46,7 @@ import { WebCameraInputWidgetComponent } from './lib/web-camera-input.component'
45 DateRangeNavigatorWidgetComponent, 46 DateRangeNavigatorWidgetComponent,
46 DateRangeNavigatorPanelComponent, 47 DateRangeNavigatorPanelComponent,
47 MultipleInputWidgetComponent, 48 MultipleInputWidgetComponent,
  49 + TripAnimationComponent,
48 WebCameraInputWidgetComponent 50 WebCameraInputWidgetComponent
49 ], 51 ],
50 imports: [ 52 imports: [
@@ -61,6 +63,7 @@ import { WebCameraInputWidgetComponent } from './lib/web-camera-input.component' @@ -61,6 +63,7 @@ import { WebCameraInputWidgetComponent } from './lib/web-camera-input.component'
61 RpcWidgetsModule, 63 RpcWidgetsModule,
62 DateRangeNavigatorWidgetComponent, 64 DateRangeNavigatorWidgetComponent,
63 MultipleInputWidgetComponent, 65 MultipleInputWidgetComponent,
  66 + TripAnimationComponent,
64 WebCameraInputWidgetComponent 67 WebCameraInputWidgetComponent
65 ], 68 ],
66 providers: [ 69 providers: [
@@ -14,13 +14,13 @@ @@ -14,13 +14,13 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import {Component, Inject, OnInit} from "@angular/core";  
18 -import {DialogComponent} from "@shared/components/dialog.component";  
19 -import {Store} from "@ngrx/store";  
20 -import {AppState} from "@core/core.state";  
21 -import {Router} from "@angular/router";  
22 -import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";  
23 -import {FormBuilder, FormGroup} from "@angular/forms"; 17 +import {Component, Inject, OnInit} from '@angular/core';
  18 +import {DialogComponent} from '@shared/components/dialog.component';
  19 +import {Store} from '@ngrx/store';
  20 +import {AppState} from '@core/core.state';
  21 +import {Router} from '@angular/router';
  22 +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
  23 +import {FormBuilder, FormGroup} from '@angular/forms';
24 24
25 export interface JsonObjectEdittDialogData { 25 export interface JsonObjectEdittDialogData {
26 jsonValue: Object; 26 jsonValue: Object;
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import {Directive, ElementRef, forwardRef, HostListener, Renderer2, SkipSelf} from "@angular/core"; 17 +import {Directive, ElementRef, forwardRef, HostListener, Renderer2, SkipSelf} from '@angular/core';
18 import { 18 import {
19 ControlValueAccessor, 19 ControlValueAccessor,
20 FormControl, FormGroupDirective, 20 FormControl, FormGroupDirective,
@@ -22,8 +22,8 @@ import { @@ -22,8 +22,8 @@ import {
22 NG_VALUE_ACCESSOR, NgForm, 22 NG_VALUE_ACCESSOR, NgForm,
23 ValidationErrors, 23 ValidationErrors,
24 Validator 24 Validator
25 -} from "@angular/forms";  
26 -import {ErrorStateMatcher} from "@angular/material/core"; 25 +} from '@angular/forms';
  26 +import {ErrorStateMatcher} from '@angular/material/core';
27 27
28 @Directive({ 28 @Directive({
29 selector: '[tb-json-to-string]', 29 selector: '[tb-json-to-string]',
@@ -113,7 +113,7 @@ const canonicalTitleMap = (titleMap: any, originalEnum?: string[]): { name: stri @@ -113,7 +113,7 @@ const canonicalTitleMap = (titleMap: any, originalEnum?: string[]): { name: stri
113 113
114 const stdFormObj = (name: string, schema: any, options: DefaultsFormOptions): any => { 114 const stdFormObj = (name: string, schema: any, options: DefaultsFormOptions): any => {
115 options = options || {}; 115 options = options || {};
116 - const f = options.global && options.global.formDefaults ? _.cloneDeep(options.global.formDefaults) : {}; 116 + const f: any = options.global && options.global.formDefaults ? _.cloneDeep(options.global.formDefaults) : {};
117 if (options.global && options.global.supressPropertyTitles === true) { 117 if (options.global && options.global.supressPropertyTitles === true) {
118 f.title = schema.title; 118 f.title = schema.title;
119 } else { 119 } else {
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div class="trip-animation-control-panel">
  19 + <div>
  20 + <button mat-icon-button class="mat-icon-button" aria-label="Start" (click)="moveStart()">
  21 + <mat-icon class="material-icons" [ngStyle]="{'color': settings.buttonColor}">fast_rewind</mat-icon>
  22 + </button>
  23 + <button mat-icon-button class="mat-icon-button" aria-label="Previous" (click)="movePrev()">
  24 + <mat-icon class="material-icons" [ngStyle]="{'color': settings.buttonColor}">skip_previous</mat-icon>
  25 + </button>
  26 + <mat-slider [(ngModel)]="index" [min]="minTimeIndex" [max]="maxTimeIndex" (change)="changeIndex()">
  27 + </mat-slider>
  28 + <button mat-icon-button class="mat-icon-button" aria-label="Next" (click)="moveNext()">
  29 + <mat-icon class="material-icons" [ngStyle]="{'color': settings.buttonColor}">skip_next</mat-icon>
  30 + </button>
  31 + <button mat-icon-button class="mat-icon-button" aria-label="End" (click)="moveEnd()">
  32 + <mat-icon class="material-icons" [ngStyle]="{'color': settings.buttonColor}">fast_forward</mat-icon>
  33 + </button>
  34 + <button mat-icon-button class="mat-icon-button" aria-label="Play">
  35 + <mat-icon (click)="play()" *ngIf="!playing" class="material-icons"
  36 + [ngStyle]="{'color': settings.buttonColor}">
  37 + play_circle_outline
  38 + </mat-icon>
  39 + <mat-icon (click)="pause()" *ngIf="playing" class="material-icons"
  40 + [ngStyle]="{'color': settings.buttonColor}">
  41 + pause_circle_outline
  42 + </mat-icon>
  43 + </button>
  44 + <mat-select matInput [(ngModel)]="speed" (selectionChange)="reeneble()" class="speed-select" aria-label="Speed selector">
  45 + <mat-option [value]="speedValue" flex="1" *ngFor="let speedValue of speeds">{{speedValue}} </mat-option>
  46 + </mat-select>
  47 + </div>
  48 + <div class="panel-timer">
  49 + <span *ngIf="this.intervals[this.index]">{{ this.intervals[this.index] | date:'medium'}}</span>
  50 + <span *ngIf="!this.intervals[this.index]">{{ "widget.no-data-found" | translate}}</span>
  51 + </div>
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +.trip-animation-widget {
  17 + position: relative;
  18 + width: 100%;
  19 + height: 100%;
  20 + font-size: 16px;
  21 + line-height: 24px;
  22 +
  23 + .trip-animation-label-container {
  24 + height: 24px;
  25 + }
  26 +
  27 + .trip-animation-container {
  28 + position: relative;
  29 + z-index: 1;
  30 + flex: 1;
  31 + width: 100%;
  32 +
  33 + #trip-animation-map {
  34 + z-index: 1;
  35 + width: 100%;
  36 + height: 100%;
  37 +
  38 + .pointsLayerMarkerIcon {
  39 + border-radius: 50%;
  40 + }
  41 + }
  42 +
  43 + .trip-animation-info-panel {
  44 + position: absolute;
  45 + top: 0;
  46 + right: 0;
  47 + z-index: 2;
  48 + pointer-events: none;
  49 +
  50 + .md-button {
  51 + top: 0;
  52 + left: 0;
  53 + width: 32px;
  54 + min-width: 32px;
  55 + height: 32px;
  56 + min-height: 32px;
  57 + padding: 0 0 2px;
  58 + margin: 2px;
  59 + line-height: 24px;
  60 +
  61 + ng-md-icon {
  62 + width: 24px;
  63 + height: 24px;
  64 +
  65 + svg {
  66 + width: inherit;
  67 + height: inherit;
  68 + }
  69 + }
  70 + }
  71 + }
  72 +
  73 + .trip-animation-tooltip {
  74 + position: absolute;
  75 + top: 38px;
  76 + right: 0;
  77 + z-index: 2;
  78 + padding: 10px;
  79 + background-color: #fff;
  80 + transition: 0.3s ease-in-out;
  81 +
  82 + &-hidden {
  83 + transform: translateX(110%);
  84 + }
  85 + }
  86 + }
  87 +
  88 + .trip-animation-control-panel {
  89 + position: relative;
  90 + box-sizing: border-box;
  91 + width: 100%;
  92 + padding-bottom: 16px;
  93 + padding-left: 10px;
  94 +
  95 + md-slider-container {
  96 + md-slider {
  97 + min-width: 80px;
  98 + }
  99 +
  100 + button.md-button.md-icon-button {
  101 + width: 44px;
  102 + min-width: 44px;
  103 + height: 44px;
  104 + min-height: 44px;
  105 + margin: 0;
  106 + line-height: 28px;
  107 +
  108 + md-icon {
  109 + width: 28px;
  110 + height: 28px;
  111 + font-size: 28px;
  112 +
  113 + svg {
  114 + width: inherit;
  115 + height: inherit;
  116 + }
  117 + }
  118 + }
  119 +
  120 + md-select {
  121 + margin: 0;
  122 + }
  123 + }
  124 +
  125 + .panel-timer {
  126 + max-width: none;
  127 + padding-right: 250px;
  128 + padding-left: 90px;
  129 + margin-top: -20px;
  130 + font-size: 12px;
  131 + font-weight: 500;
  132 + text-align: center;
  133 + }
  134 + }
  135 +}
  136 +
  137 +.speed-select{
  138 + width: 50px;
  139 + margin-left: 20px;
  140 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
  18 +import { interval, Subscription, Subscriber, SubscriptionLike, Observer } from 'rxjs';
  19 +import { filter, tap } from 'rxjs/operators';
  20 +import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/maps/map-models';
  21 +
  22 +@Component({
  23 + selector: 'tb-history-selector',
  24 + templateUrl: './history-selector.component.html',
  25 + styleUrls: ['./history-selector.component.scss']
  26 +})
  27 +export class HistorySelectorComponent implements OnInit, OnChanges {
  28 +
  29 + @Input() settings: HistorySelectSettings
  30 + @Input() intervals = [];
  31 +
  32 + @Output() timeUpdated: EventEmitter<number> = new EventEmitter();
  33 +
  34 + animationTime;
  35 + minTimeIndex = 0;
  36 + maxTimeIndex = 0;
  37 + speed = 1;
  38 + index = 0;
  39 + playing = false;
  40 + interval;
  41 + speeds = [1, 5, 10, 25];
  42 +
  43 +
  44 + constructor(private cd: ChangeDetectorRef) { }
  45 +
  46 + ngOnInit(): void {
  47 + }
  48 +
  49 + ngOnChanges() {
  50 + this.maxTimeIndex = this.intervals?.length - 1;
  51 + }
  52 +
  53 + play() {
  54 + this.playing = true;
  55 + if (!this.interval)
  56 + this.interval = interval(1000 / this.speed)
  57 + .pipe(
  58 + filter(() => this.playing),
  59 + tap(() => this.index++)).subscribe(() => {
  60 + if (this.index < this.maxTimeIndex) {
  61 + this.cd.detectChanges();
  62 + this.timeUpdated.emit(this.intervals[this.index]);
  63 + }
  64 + else {
  65 + this.interval.complete();
  66 + }
  67 + }, err => {
  68 + console.log(err);
  69 + }, () => {
  70 + this.index = this.minTimeIndex;
  71 + this.playing = false;
  72 + this.interval = null;
  73 + this.cd.detectChanges();
  74 + });
  75 + }
  76 +
  77 + reeneble() {
  78 + if (this.playing) {
  79 + const position = this.index;
  80 + this.interval.complete();
  81 + this.index = position;
  82 + this.play();
  83 + }
  84 + }
  85 +
  86 + pause() {
  87 + this.playing = false;
  88 + this.cd.detectChanges();
  89 + this.timeUpdated.emit(this.intervals[this.index]);
  90 + }
  91 +
  92 + moveNext() {
  93 + if (this.index < this.maxTimeIndex) {
  94 + this.index++;
  95 + }
  96 + this.pause();
  97 + }
  98 +
  99 + movePrev() {
  100 + if (this.index > this.minTimeIndex) {
  101 + this.index++;
  102 + }
  103 + this.pause();
  104 + }
  105 +
  106 + moveStart() {
  107 + this.index = this.minTimeIndex;
  108 + this.pause();
  109 + }
  110 +
  111 + moveEnd() {
  112 + this.index = this.maxTimeIndex;
  113 + this.pause();
  114 + }
  115 +
  116 + changeIndex() {
  117 + this.timeUpdated.emit(this.intervals[this.index]);
  118 + }
  119 +}
@@ -17,12 +17,12 @@ @@ -17,12 +17,12 @@
17 import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; 17 import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
18 import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm } from '@angular/forms'; 18 import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm } from '@angular/forms';
19 import { ValueType, valueTypesMap } from '@shared/models/constants'; 19 import { ValueType, valueTypesMap } from '@shared/models/constants';
20 -import { isObject } from "@core/utils";  
21 -import { MatDialog } from "@angular/material/dialog"; 20 +import { isObject } from '@core/utils';
  21 +import { MatDialog } from '@angular/material/dialog';
22 import { 22 import {
23 JsonObjectEditDialogComponent, 23 JsonObjectEditDialogComponent,
24 JsonObjectEdittDialogData 24 JsonObjectEdittDialogData
25 -} from "@shared/components/dialog/json-object-edit-dialog.component"; 25 +} from '@shared/components/dialog/json-object-edit-dialog.component';
26 26
27 @Component({ 27 @Component({
28 selector: 'tb-value-input', 28 selector: 'tb-value-input',
@@ -79,7 +79,7 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor { @@ -79,7 +79,7 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor {
79 (res) => { 79 (res) => {
80 if (res) { 80 if (res) {
81 this.modelValue = res; 81 this.modelValue = res;
82 - this.inputForm.control.patchValue({'value': this.modelValue}); 82 + this.inputForm.control.patchValue({value: this.modelValue});
83 } 83 }
84 } 84 }
85 ); 85 );
@@ -20,3 +20,4 @@ export * from './keyboard-shortcut.pipe'; @@ -20,3 +20,4 @@ export * from './keyboard-shortcut.pipe';
20 export * from './milliseconds-to-time-string.pipe'; 20 export * from './milliseconds-to-time-string.pipe';
21 export * from './nospace.pipe'; 21 export * from './nospace.pipe';
22 export * from './truncate.pipe'; 22 export * from './truncate.pipe';
  23 +export * from './template.pipe';
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 /// 15 ///
16 16
17 import {Pipe, PipeTransform} from '@angular/core'; 17 import {Pipe, PipeTransform} from '@angular/core';
18 -import {isObject, isNumber} from "@core/utils"; 18 +import {isObject, isNumber} from '@core/utils';
19 19
20 @Pipe({name: 'tbJson'}) 20 @Pipe({name: 'tbJson'})
21 export class TbJsonPipe implements PipeTransform { 21 export class TbJsonPipe implements PipeTransform {
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Pipe, PipeTransform } from '@angular/core';
  18 +import { parseTemplate } from '@app/core/utils';
  19 +
  20 +@Pipe({ name: 'tbParseTemplate' })
  21 +export class TbTemplatePipe implements PipeTransform {
  22 + transform(template, data): string {
  23 + console.log('TbTemplatePipe -> transform -> template, data', template, data)
  24 + return parseTemplate(template, data);
  25 + }
  26 +}
@@ -104,7 +104,7 @@ import { TbErrorComponent } from '@shared/components/tb-error.component'; @@ -104,7 +104,7 @@ import { TbErrorComponent } from '@shared/components/tb-error.component';
104 import { EntityTypeListComponent } from '@shared/components/entity/entity-type-list.component'; 104 import { EntityTypeListComponent } from '@shared/components/entity/entity-type-list.component';
105 import { EntitySubTypeListComponent } from '@shared/components/entity/entity-subtype-list.component'; 105 import { EntitySubTypeListComponent } from '@shared/components/entity/entity-subtype-list.component';
106 import { TruncatePipe } from '@shared/pipe/truncate.pipe'; 106 import { TruncatePipe } from '@shared/pipe/truncate.pipe';
107 -import { TbJsonPipe } from "@shared/pipe/tbJson.pipe"; 107 +import { TbJsonPipe } from '@shared/pipe/tbJson.pipe';
108 import { ColorPickerDialogComponent } from '@shared/components/dialog/color-picker-dialog.component'; 108 import { ColorPickerDialogComponent } from '@shared/components/dialog/color-picker-dialog.component';
109 import { MatChipDraggableDirective } from '@shared/components/mat-chip-draggable.directive'; 109 import { MatChipDraggableDirective } from '@shared/components/mat-chip-draggable.directive';
110 import { ColorInputComponent } from '@shared/components/color-input.component'; 110 import { ColorInputComponent } from '@shared/components/color-input.component';
@@ -125,8 +125,10 @@ import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component'; @@ -125,8 +125,10 @@ import { TbCheatSheetComponent } from '@shared/components/cheatsheet.component';
125 import { TbHotkeysDirective } from '@shared/components/hotkeys.directive'; 125 import { TbHotkeysDirective } from '@shared/components/hotkeys.directive';
126 import { NavTreeComponent } from '@shared/components/nav-tree.component'; 126 import { NavTreeComponent } from '@shared/components/nav-tree.component';
127 import { LedLightComponent } from '@shared/components/led-light.component'; 127 import { LedLightComponent } from '@shared/components/led-light.component';
128 -import { TbJsonToStringDirective } from "@shared/components/directives/tb-json-to-string.directive";  
129 -import { JsonObjectEditDialogComponent } from "@shared/components/dialog/json-object-edit-dialog.component"; 128 +import { TbJsonToStringDirective } from '@shared/components/directives/tb-json-to-string.directive';
  129 +import { JsonObjectEditDialogComponent } from '@shared/components/dialog/json-object-edit-dialog.component';
  130 +import { HistorySelectorComponent } from './components/time/history-selector/history-selector.component';
  131 +import { TbTemplatePipe } from './pipe/public-api';
130 132
131 @NgModule({ 133 @NgModule({
132 providers: [ 134 providers: [
@@ -207,9 +209,11 @@ import { JsonObjectEditDialogComponent } from "@shared/components/dialog/json-ob @@ -207,9 +209,11 @@ import { JsonObjectEditDialogComponent } from "@shared/components/dialog/json-ob
207 HighlightPipe, 209 HighlightPipe,
208 TruncatePipe, 210 TruncatePipe,
209 TbJsonPipe, 211 TbJsonPipe,
  212 + TbTemplatePipe,
210 KeyboardShortcutPipe, 213 KeyboardShortcutPipe,
211 TbJsonToStringDirective, 214 TbJsonToStringDirective,
212 - JsonObjectEditDialogComponent 215 + JsonObjectEditDialogComponent,
  216 + HistorySelectorComponent
213 ], 217 ],
214 imports: [ 218 imports: [
215 CommonModule, 219 CommonModule,
@@ -365,9 +369,11 @@ import { JsonObjectEditDialogComponent } from "@shared/components/dialog/json-ob @@ -365,9 +369,11 @@ import { JsonObjectEditDialogComponent } from "@shared/components/dialog/json-ob
365 HighlightPipe, 369 HighlightPipe,
366 TruncatePipe, 370 TruncatePipe,
367 TbJsonPipe, 371 TbJsonPipe,
  372 + TbTemplatePipe,
368 KeyboardShortcutPipe, 373 KeyboardShortcutPipe,
369 TranslateModule, 374 TranslateModule,
370 - JsonObjectEditDialogComponent 375 + JsonObjectEditDialogComponent,
  376 + HistorySelectorComponent
371 ] 377 ]
372 }) 378 })
373 export class SharedModule { } 379 export class SharedModule { }
  1 +<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M24 4c-7.72 0-14 6.28-14 14 0 10.5 14 26 14 26s14-15.5 14-26c0-7.72-6.28-14-14-14zm8 16h-6v6h-4v-6h-6v-4h6v-6h4v6h6v4z"/></svg>
@@ -93,6 +93,8 @@ import { TbAnalogueCompass } from '@home/components/widget/lib/analogue-compass' @@ -93,6 +93,8 @@ import { TbAnalogueCompass } from '@home/components/widget/lib/analogue-compass'
93 import { TbAnalogueRadialGauge } from '@home/components/widget/lib/analogue-radial-gauge'; 93 import { TbAnalogueRadialGauge } from '@home/components/widget/lib/analogue-radial-gauge';
94 import { TbAnalogueLinearGauge } from '@home/components/widget/lib/analogue-linear-gauge'; 94 import { TbAnalogueLinearGauge } from '@home/components/widget/lib/analogue-linear-gauge';
95 import { TbCanvasDigitalGauge } from '@home/components/widget/lib/digital-gauge'; 95 import { TbCanvasDigitalGauge } from '@home/components/widget/lib/digital-gauge';
  96 +import { TbMapWidgetV2 } from '@home/components/widget/lib/maps/map-widget2';
  97 +import { TbTripAnimationWidget } from '@app/modules/home/components/widget/trip-animation/trip-animation.component';
96 98
97 import * as tinycolor_ from 'tinycolor2'; 99 import * as tinycolor_ from 'tinycolor2';
98 100
@@ -106,3 +108,5 @@ const tinycolor = tinycolor_; @@ -106,3 +108,5 @@ const tinycolor = tinycolor_;
106 (window as any).TbAnalogueRadialGauge = TbAnalogueRadialGauge; 108 (window as any).TbAnalogueRadialGauge = TbAnalogueRadialGauge;
107 (window as any).TbAnalogueLinearGauge = TbAnalogueLinearGauge; 109 (window as any).TbAnalogueLinearGauge = TbAnalogueLinearGauge;
108 (window as any).TbCanvasDigitalGauge = TbCanvasDigitalGauge; 110 (window as any).TbCanvasDigitalGauge = TbCanvasDigitalGauge;
  111 +(window as any).TbMapWidgetV2 = TbMapWidgetV2;
  112 +(window as any).TbTripAnimationWidget = TbTripAnimationWidget;
  1 +import * as L from 'leaflet'
  2 +
  3 +declare module 'leaflet' {
  4 +
  5 + namespace Control {
  6 + class AddMarker extends L.Control { }
  7 + }
  8 +
  9 + namespace control {
  10 + function addMarker(options): Control.AddMarker;
  11 + }
  12 +}
@@ -19,7 +19,8 @@ @@ -19,7 +19,8 @@
19 "src/typings/jquery.typings.d.ts", 19 "src/typings/jquery.typings.d.ts",
20 "src/typings/jquery.flot.typings.d.ts", 20 "src/typings/jquery.flot.typings.d.ts",
21 "src/typings/jquery.jstree.typings.d.ts", 21 "src/typings/jquery.jstree.typings.d.ts",
22 - "src/typings/split.js.typings.d.ts" 22 + "src/typings/split.js.typings.d.ts",
  23 + "src/typings/add-marker.d.ts"
23 ], 24 ],
24 "paths": { 25 "paths": {
25 "@app/*": ["src/app/*"], 26 "@app/*": ["src/app/*"],
@@ -33,6 +34,7 @@ @@ -33,6 +34,7 @@
33 }, 34 },
34 "lib": [ 35 "lib": [
35 "es2018", 36 "es2018",
  37 + "es2019",
36 "dom" 38 "dom"
37 ] 39 ]
38 } 40 }
@@ -433,7 +433,7 @@ export default class TbMapWidgetV2 { @@ -433,7 +433,7 @@ export default class TbMapWidgetV2 {
433 function calculateLocationColor(location, dataMap) { 433 function calculateLocationColor(location, dataMap) {
434 if (location.settings.useColorFunction && location.settings.colorFunction) { 434 if (location.settings.useColorFunction && location.settings.colorFunction) {
435 var color; 435 var color;
436 - try { 436 + try {
437 color = location.settings.colorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex); 437 color = location.settings.colorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex);
438 } catch (e) {/**/ 438 } catch (e) {/**/
439 } 439 }
@@ -450,7 +450,7 @@ export default class TbMapWidgetV2 { @@ -450,7 +450,7 @@ export default class TbMapWidgetV2 {
450 if (location.settings.usePolygonColorFunction && location.settings.polygonColorFunction) { 450 if (location.settings.usePolygonColorFunction && location.settings.polygonColorFunction) {
451 var color; 451 var color;
452 try { 452 try {
453 - color = location.settings.polygonColorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex); 453 + color = location.settings.polygonColorFunction(dataMap.dataMap, dataMap.dsDataMap, location.dsIndex);
454 } catch (e) {/**/ 454 } catch (e) {/**/
455 } 455 }
456 if (!color) { 456 if (!color) {
@@ -484,7 +484,7 @@ export default class TbMapWidgetV2 { @@ -484,7 +484,7 @@ export default class TbMapWidgetV2 {
484 function calculateLocationMarkerImage(location, dataMap) { 484 function calculateLocationMarkerImage(location, dataMap) {
485 if (location.settings.useMarkerImageFunction && location.settings.markerImageFunction) { 485 if (location.settings.useMarkerImageFunction && location.settings.markerImageFunction) {
486 var image = null; 486 var image = null;
487 - try { 487 + try {
488 image = location.settings.markerImageFunction(dataMap.dataMap, location.settings.markerImages, dataMap.dsDataMap, location.dsIndex); 488 image = location.settings.markerImageFunction(dataMap.dataMap, location.settings.markerImages, dataMap.dsDataMap, location.dsIndex);
489 } catch (e) { 489 } catch (e) {
490 image = null; 490 image = null;