committed by
GitHub
273 changed files with 15599 additions and 109 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,105 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@shared/public-api'; |
|||
import { HomeComponentsModule } from '@home/components/public-api'; |
|||
import { AttributesConfigComponent } from './attributes-config.component'; |
|||
import { TimeseriesConfigComponent } from './timeseries-config.component'; |
|||
import { RpcRequestConfigComponent } from './rpc-request-config.component'; |
|||
import { LogConfigComponent } from './log-config.component'; |
|||
import { AssignCustomerConfigComponent } from './assign-customer-config.component'; |
|||
import { ClearAlarmConfigComponent } from './clear-alarm-config.component'; |
|||
import { CreateAlarmConfigComponent } from './create-alarm-config.component'; |
|||
import { CreateRelationConfigComponent } from './create-relation-config.component'; |
|||
import { MsgDelayConfigComponent } from './msg-delay-config.component'; |
|||
import { DeleteRelationConfigComponent } from './delete-relation-config.component'; |
|||
import { GeneratorConfigComponent } from './generator-config.component'; |
|||
import { GpsGeoActionConfigComponent } from './gps-geo-action-config.component'; |
|||
import { MsgCountConfigComponent } from './msg-count-config.component'; |
|||
import { RpcReplyConfigComponent } from './rpc-reply-config.component'; |
|||
import { SaveToCustomTableConfigComponent } from './save-to-custom-table-config.component'; |
|||
import { CommonRuleNodeConfigModule } from '../common/common-rule-node-config.module'; |
|||
import { UnassignCustomerConfigComponent } from './unassign-customer-config.component'; |
|||
import { DeviceProfileConfigComponent } from './device-profile-config.component'; |
|||
import { PushToEdgeConfigComponent } from './push-to-edge-config.component'; |
|||
import { PushToCloudConfigComponent } from './push-to-cloud-config.component'; |
|||
import { DeleteAttributesConfigComponent } from './delete-attributes-config.component'; |
|||
import { MathFunctionConfigComponent } from './math-function-config.component'; |
|||
import { DeviceStateConfigComponent } from './device-state-config.component'; |
|||
import { SendRestApiCallReplyConfigComponent } from './send-rest-api-call-reply-config.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
DeleteAttributesConfigComponent, |
|||
AttributesConfigComponent, |
|||
TimeseriesConfigComponent, |
|||
RpcRequestConfigComponent, |
|||
LogConfigComponent, |
|||
AssignCustomerConfigComponent, |
|||
ClearAlarmConfigComponent, |
|||
CreateAlarmConfigComponent, |
|||
CreateRelationConfigComponent, |
|||
MsgDelayConfigComponent, |
|||
DeleteRelationConfigComponent, |
|||
GeneratorConfigComponent, |
|||
GpsGeoActionConfigComponent, |
|||
MsgCountConfigComponent, |
|||
RpcReplyConfigComponent, |
|||
SaveToCustomTableConfigComponent, |
|||
UnassignCustomerConfigComponent, |
|||
SendRestApiCallReplyConfigComponent, |
|||
DeviceProfileConfigComponent, |
|||
PushToEdgeConfigComponent, |
|||
PushToCloudConfigComponent, |
|||
MathFunctionConfigComponent, |
|||
DeviceStateConfigComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
HomeComponentsModule, |
|||
CommonRuleNodeConfigModule |
|||
], |
|||
exports: [ |
|||
DeleteAttributesConfigComponent, |
|||
AttributesConfigComponent, |
|||
TimeseriesConfigComponent, |
|||
RpcRequestConfigComponent, |
|||
LogConfigComponent, |
|||
AssignCustomerConfigComponent, |
|||
ClearAlarmConfigComponent, |
|||
CreateAlarmConfigComponent, |
|||
CreateRelationConfigComponent, |
|||
MsgDelayConfigComponent, |
|||
DeleteRelationConfigComponent, |
|||
GeneratorConfigComponent, |
|||
GpsGeoActionConfigComponent, |
|||
MsgCountConfigComponent, |
|||
RpcReplyConfigComponent, |
|||
SaveToCustomTableConfigComponent, |
|||
UnassignCustomerConfigComponent, |
|||
SendRestApiCallReplyConfigComponent, |
|||
DeviceProfileConfigComponent, |
|||
PushToEdgeConfigComponent, |
|||
PushToCloudConfigComponent, |
|||
MathFunctionConfigComponent, |
|||
DeviceStateConfigComponent |
|||
] |
|||
}) |
|||
export class ActionRuleNodeConfigModule { |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="assignCustomerConfigForm" class="flex flex-col"> |
|||
<div class="tb-form-panel no-padding no-border"> |
|||
<mat-form-field class="mat-block" subscriptSizing="dynamic"> |
|||
<mat-label translate>rule-node-config.customer-name-pattern</mat-label> |
|||
<input required matInput formControlName="customerNamePattern"> |
|||
<mat-error *ngIf="assignCustomerConfigForm.get('customerNamePattern').hasError('required') || |
|||
assignCustomerConfigForm.get('customerNamePattern').hasError('pattern')"> |
|||
{{ 'rule-node-config.customer-name-pattern-required' | translate }} |
|||
</mat-error> |
|||
<mat-hint translate>rule-node-config.customer-name-pattern-hint</mat-hint> |
|||
</mat-form-field> |
|||
<div class="tb-form-row"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="createCustomerIfNotExists"> |
|||
{{ 'rule-node-config.create-customer-if-not-exists' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
@ -0,0 +1,49 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@shared/models/rule-node.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-assign-to-customer-config', |
|||
templateUrl: './assign-customer-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class AssignCustomerConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
assignCustomerConfigForm: UntypedFormGroup; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.assignCustomerConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.assignCustomerConfigForm = this.fb.group({ |
|||
customerNamePattern: [configuration ? configuration.customerNamePattern : null, [Validators.required, Validators.pattern(/.*\S.*/)]], |
|||
createCustomerIfNotExists: [configuration ? configuration.createCustomerIfNotExists : false, []] |
|||
}); |
|||
} |
|||
|
|||
protected prepareOutputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
configuration.customerNamePattern = configuration.customerNamePattern.trim(); |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="attributesConfigForm" class="tb-form-panel no-border no-padding"> |
|||
<div class="tb-form-panel stroked"> |
|||
<tb-example-hint [hintText]="'rule-node-config.attributes-scope-hint'"> |
|||
</tb-example-hint> |
|||
<div class="tb-form-row no-border no-padding tb-standard-fields"> |
|||
<mat-form-field class="flex"> |
|||
<mat-label>{{ 'rule-node-config.attributes-scope' | translate }}</mat-label> |
|||
<mat-select required |
|||
class="tb-entity-type-select" matInput formControlName="scope"> |
|||
<mat-option *ngFor="let scope of attributeScopes" [value]="scope"> |
|||
{{ telemetryTypeTranslationsMap.get(scope) | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<mat-form-field class="flex"> |
|||
<mat-label>{{ 'rule-node-config.attributes-scope-value' | translate }}</mat-label> |
|||
<input type="text" matInput readonly disabled [ngModel]="attributesConfigForm.get('scope').value" [ngModelOptions]="{standalone: true}"> |
|||
<button type="button" |
|||
matSuffix |
|||
mat-icon-button |
|||
aria-label="Copy" |
|||
ngxClipboard |
|||
[cbContent]="attributesConfigForm.get('scope').value" |
|||
matTooltip="{{ 'rule-node-config.attributes-scope-value-copy' | translate }}"> |
|||
<mat-icon aria-hidden="false" |
|||
aria-label="help-icon">content_copy |
|||
</mat-icon> |
|||
</button> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
|
|||
<section class="tb-form-panel stroked"> |
|||
<mat-expansion-panel class="tb-settings"> |
|||
<mat-expansion-panel-header> |
|||
<mat-panel-title translate>rule-node-config.advanced-settings</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
<div tb-hint-tooltip-icon="{{ (attributesConfigForm.get('updateAttributesOnlyOnValueChange').value |
|||
? 'rule-node-config.update-attributes-only-on-value-change-hint-enabled' |
|||
: 'rule-node-config.update-attributes-only-on-value-change-hint') | translate }}" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="updateAttributesOnlyOnValueChange"> |
|||
{{ 'rule-node-config.update-attributes-only-on-value-change' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.send-attributes-updated-notification-hint' | translate }}" |
|||
*ngIf="attributesConfigForm.get('scope').value !== attributeScopeMap.CLIENT_SCOPE" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="sendAttributesUpdatedNotification"> |
|||
{{ 'rule-node-config.send-attributes-updated-notification' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.notify-device-on-update-hint' | translate }}" |
|||
*ngIf="attributesConfigForm.get('scope').value === attributeScopeMap.SHARED_SCOPE" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="notifyDevice"> |
|||
{{ 'rule-node-config.notify-device' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
</mat-expansion-panel> |
|||
</section> |
|||
</section> |
|||
@ -0,0 +1,65 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@shared/models/rule-node.models'; |
|||
import { AttributeScope, telemetryTypeTranslations } from '@app/shared/models/telemetry/telemetry.models'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-attributes-config', |
|||
templateUrl: './attributes-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class AttributesConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
attributeScopeMap = AttributeScope; |
|||
attributeScopes = Object.keys(AttributeScope); |
|||
telemetryTypeTranslationsMap = telemetryTypeTranslations; |
|||
|
|||
attributesConfigForm: UntypedFormGroup; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.attributesConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.attributesConfigForm = this.fb.group({ |
|||
scope: [configuration ? configuration.scope : null, [Validators.required]], |
|||
notifyDevice: [configuration ? configuration.notifyDevice : true, []], |
|||
sendAttributesUpdatedNotification: [configuration ? configuration.sendAttributesUpdatedNotification : false, []], |
|||
updateAttributesOnlyOnValueChange: [configuration ? configuration.updateAttributesOnlyOnValueChange : false, []] |
|||
}); |
|||
|
|||
this.attributesConfigForm.get('scope').valueChanges.pipe( |
|||
takeUntilDestroyed(this.destroyRef) |
|||
).subscribe((value) => { |
|||
if (value !== AttributeScope.SHARED_SCOPE) { |
|||
this.attributesConfigForm.get('notifyDevice').patchValue(false, {emitEvent: false}); |
|||
} |
|||
if (value === AttributeScope.CLIENT_SCOPE) { |
|||
this.attributesConfigForm.get('sendAttributesUpdatedNotification').patchValue(false, {emitEvent: false}); |
|||
} |
|||
this.attributesConfigForm.get('updateAttributesOnlyOnValueChange').patchValue(false, {emitEvent: false}); |
|||
}); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="clearAlarmConfigForm" class="flex flex-col"> |
|||
<tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang> |
|||
<tb-js-func *ngIf="clearAlarmConfigForm.get('scriptLang').value === scriptLanguage.JS" |
|||
#jsFuncComponent |
|||
formControlName="alarmDetailsBuildJs" |
|||
functionName="Details" |
|||
[functionArgs]="['msg', 'metadata', 'msgType']" |
|||
helpId="rulenode/clear_alarm_node_script_fn" |
|||
noValidate="true"> |
|||
<button toolbarSuffixButton |
|||
mat-icon-button |
|||
matTooltip="{{ testScriptLabel | translate }}" |
|||
matTooltipPosition="above" |
|||
class="tb-mat-32" |
|||
(click)="testScript()"> |
|||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon> |
|||
</button> |
|||
</tb-js-func> |
|||
<tb-js-func *ngIf="clearAlarmConfigForm.get('scriptLang').value === scriptLanguage.TBEL" |
|||
#tbelFuncComponent |
|||
formControlName="alarmDetailsBuildTbel" |
|||
functionName="Details" |
|||
[functionArgs]="['msg', 'metadata', 'msgType']" |
|||
[disableUndefinedCheck]="true" |
|||
[scriptLanguage]="scriptLanguage.TBEL" |
|||
helpId="rulenode/tbel/clear_alarm_node_script_fn" |
|||
noValidate="true"> |
|||
<button toolbarSuffixButton |
|||
mat-icon-button |
|||
matTooltip="{{ testScriptLabel | translate }}" |
|||
matTooltipPosition="above" |
|||
class="tb-mat-32" |
|||
(click)="testScript()"> |
|||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon> |
|||
</button> |
|||
</tb-js-func> |
|||
<div class="flex flex-row" style="padding-bottom: 16px;"> |
|||
<button mat-button mat-raised-button color="primary" (click)="testScript()"> |
|||
{{ testScriptLabel | translate }} |
|||
</button> |
|||
</div> |
|||
<mat-form-field class="mat-block" subscriptSizing="dynamic"> |
|||
<mat-label translate>rule-node-config.alarm-type</mat-label> |
|||
<input required matInput formControlName="alarmType"> |
|||
<mat-error *ngIf="clearAlarmConfigForm.get('alarmType').hasError('required')"> |
|||
{{ 'rule-node-config.alarm-type-required' | translate }} |
|||
</mat-error> |
|||
<mat-hint translate>rule-node-config.general-pattern-hint</mat-hint> |
|||
</mat-form-field> |
|||
</section> |
|||
@ -0,0 +1,127 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, EventEmitter, ViewChild } from '@angular/core'; |
|||
import { AppState, getCurrentAuthState, NodeScriptTestService } from '@core/public-api'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { |
|||
RuleNodeConfiguration, |
|||
RuleNodeConfigurationComponent, |
|||
ScriptLanguage |
|||
} from '@app/shared/models/rule-node.models'; |
|||
import type { JsFuncComponent } from '@app/shared/components/js-func.component'; |
|||
import { DebugRuleNodeEventBody } from '@shared/models/event.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-clear-alarm-config', |
|||
templateUrl: './clear-alarm-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class ClearAlarmConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
@ViewChild('jsFuncComponent', {static: false}) jsFuncComponent: JsFuncComponent; |
|||
@ViewChild('tbelFuncComponent', {static: false}) tbelFuncComponent: JsFuncComponent; |
|||
|
|||
clearAlarmConfigForm: UntypedFormGroup; |
|||
|
|||
tbelEnabled = getCurrentAuthState(this.store).tbelEnabled; |
|||
|
|||
scriptLanguage = ScriptLanguage; |
|||
|
|||
changeScript: EventEmitter<void> = new EventEmitter<void>(); |
|||
|
|||
readonly hasScript = true; |
|||
|
|||
readonly testScriptLabel = 'rule-node-config.test-details-function'; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private fb: UntypedFormBuilder, |
|||
private nodeScriptTestService: NodeScriptTestService, |
|||
private translate: TranslateService) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.clearAlarmConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.clearAlarmConfigForm = this.fb.group({ |
|||
scriptLang: [configuration ? configuration.scriptLang : ScriptLanguage.JS, [Validators.required]], |
|||
alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, []], |
|||
alarmDetailsBuildTbel: [configuration ? configuration.alarmDetailsBuildTbel : null, []], |
|||
alarmType: [configuration ? configuration.alarmType : null, [Validators.required]] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['scriptLang']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
let scriptLang: ScriptLanguage = this.clearAlarmConfigForm.get('scriptLang').value; |
|||
if (scriptLang === ScriptLanguage.TBEL && !this.tbelEnabled) { |
|||
scriptLang = ScriptLanguage.JS; |
|||
this.clearAlarmConfigForm.get('scriptLang').patchValue(scriptLang, {emitEvent: false}); |
|||
setTimeout(() => {this.clearAlarmConfigForm.updateValueAndValidity({emitEvent: true});}); |
|||
} |
|||
this.clearAlarmConfigForm.get('alarmDetailsBuildJs').setValidators(scriptLang === ScriptLanguage.JS ? [Validators.required] : []); |
|||
this.clearAlarmConfigForm.get('alarmDetailsBuildJs').updateValueAndValidity({emitEvent}); |
|||
this.clearAlarmConfigForm.get('alarmDetailsBuildTbel').setValidators(scriptLang === ScriptLanguage.TBEL ? [Validators.required] : []); |
|||
this.clearAlarmConfigForm.get('alarmDetailsBuildTbel').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
protected prepareInputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
if (configuration) { |
|||
if (!configuration.scriptLang) { |
|||
configuration.scriptLang = ScriptLanguage.JS; |
|||
} |
|||
} |
|||
return configuration; |
|||
} |
|||
|
|||
testScript(debugEventBody?: DebugRuleNodeEventBody) { |
|||
const scriptLang: ScriptLanguage = this.clearAlarmConfigForm.get('scriptLang').value; |
|||
const scriptField = scriptLang === ScriptLanguage.JS ? 'alarmDetailsBuildJs' : 'alarmDetailsBuildTbel'; |
|||
const helpId = scriptLang === ScriptLanguage.JS ? 'rulenode/clear_alarm_node_script_fn' : 'rulenode/tbel/clear_alarm_node_script_fn'; |
|||
const script: string = this.clearAlarmConfigForm.get(scriptField).value; |
|||
this.nodeScriptTestService.testNodeScript( |
|||
script, |
|||
'json', |
|||
this.translate.instant('rule-node-config.details'), |
|||
'Details', |
|||
['msg', 'metadata', 'msgType'], |
|||
this.ruleNodeId, |
|||
helpId, |
|||
scriptLang, |
|||
debugEventBody |
|||
).subscribe((theScript) => { |
|||
if (theScript) { |
|||
this.clearAlarmConfigForm.get(scriptField).setValue(theScript); |
|||
this.changeScript.emit(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
protected onValidate() { |
|||
const scriptLang: ScriptLanguage = this.clearAlarmConfigForm.get('scriptLang').value; |
|||
if (scriptLang === ScriptLanguage.JS) { |
|||
this.jsFuncComponent.validateOnSubmit(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="createAlarmConfigForm" class="flex flex-col"> |
|||
<mat-checkbox formControlName="useMessageAlarmData"> |
|||
{{ 'rule-node-config.use-message-alarm-data' | translate }} |
|||
</mat-checkbox> |
|||
<mat-checkbox formControlName="overwriteAlarmDetails" *ngIf="createAlarmConfigForm.get('useMessageAlarmData').value === true"> |
|||
{{ 'rule-node-config.overwrite-alarm-details' | translate }} |
|||
</mat-checkbox> |
|||
<section class="flex flex-col" *ngIf="createAlarmConfigForm.get('useMessageAlarmData').value === false || |
|||
createAlarmConfigForm.get('overwriteAlarmDetails').value === true"> |
|||
<tb-script-lang formControlName="scriptLang" *ngIf="tbelEnabled"></tb-script-lang> |
|||
<tb-js-func *ngIf="createAlarmConfigForm.get('scriptLang').value === scriptLanguage.JS" |
|||
#jsFuncComponent |
|||
formControlName="alarmDetailsBuildJs" |
|||
functionName="Details" |
|||
[functionArgs]="['msg', 'metadata', 'msgType']" |
|||
helpId="rulenode/create_alarm_node_script_fn" |
|||
noValidate="true"> |
|||
<button toolbarSuffixButton |
|||
mat-icon-button |
|||
matTooltip="{{ testScriptLabel | translate }}" |
|||
matTooltipPosition="above" |
|||
class="tb-mat-32" |
|||
(click)="testScript()"> |
|||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon> |
|||
</button> |
|||
</tb-js-func> |
|||
<tb-js-func *ngIf="createAlarmConfigForm.get('scriptLang').value === scriptLanguage.TBEL" |
|||
#tbelFuncComponent |
|||
formControlName="alarmDetailsBuildTbel" |
|||
functionName="Details" |
|||
[functionArgs]="['msg', 'metadata', 'msgType']" |
|||
[disableUndefinedCheck]="true" |
|||
[scriptLanguage]="scriptLanguage.TBEL" |
|||
helpId="rulenode/tbel/create_alarm_node_script_fn" |
|||
noValidate="true"> |
|||
<button toolbarSuffixButton |
|||
mat-icon-button |
|||
matTooltip="{{ testScriptLabel | translate }}" |
|||
matTooltipPosition="above" |
|||
class="tb-mat-32" |
|||
(click)="testScript()"> |
|||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon> |
|||
</button> |
|||
</tb-js-func> |
|||
<div class="flex flex-row" style="padding-bottom: 16px;"> |
|||
<button mat-button mat-raised-button color="primary" (click)="testScript()"> |
|||
{{ testScriptLabel | translate }} |
|||
</button> |
|||
</div> |
|||
</section> |
|||
<section class="flex flex-col" *ngIf="createAlarmConfigForm.get('useMessageAlarmData').value === false"> |
|||
<mat-form-field class="flex-1" subscriptSizing="dynamic"> |
|||
<mat-label translate>rule-node-config.alarm-type</mat-label> |
|||
<input required matInput formControlName="alarmType"> |
|||
<mat-error *ngIf="createAlarmConfigForm.get('alarmType').hasError('required')"> |
|||
{{ 'rule-node-config.alarm-type-required' | translate }} |
|||
</mat-error> |
|||
<mat-hint translate>rule-node-config.general-pattern-hint</mat-hint> |
|||
</mat-form-field> |
|||
<mat-checkbox formControlName="dynamicSeverity"> |
|||
{{ 'rule-node-config.use-alarm-severity-pattern' | translate }} |
|||
</mat-checkbox> |
|||
<mat-form-field class="flex-1" *ngIf="!createAlarmConfigForm.get('dynamicSeverity').value"> |
|||
<mat-label translate>rule-node-config.alarm-severity</mat-label> |
|||
<mat-select formControlName="severity" required> |
|||
<mat-option *ngFor="let severity of alarmSeverities" [value]="severity"> |
|||
{{ alarmSeverityTranslationMap.get(severity) | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
<mat-error *ngIf="createAlarmConfigForm.get('severity').hasError('required')"> |
|||
{{ 'rule-node-config.alarm-severity-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<mat-form-field class="flex-1" *ngIf="createAlarmConfigForm.get('dynamicSeverity').value" subscriptSizing="dynamic"> |
|||
<mat-label translate>rule-node-config.alarm-severity-pattern</mat-label> |
|||
<input matInput formControlName="severity" required> |
|||
<mat-error *ngIf="createAlarmConfigForm.get('severity').hasError('required')"> |
|||
{{ 'rule-node-config.alarm-severity-required' | translate }} |
|||
</mat-error> |
|||
<mat-hint [innerHTML]="'rule-node-config.alarm-severity-pattern-hint' | translate | safe: 'html'"></mat-hint> |
|||
</mat-form-field> |
|||
<mat-checkbox formControlName="propagate"> |
|||
{{ 'rule-node-config.propagate' | translate }} |
|||
</mat-checkbox> |
|||
<section *ngIf="createAlarmConfigForm.get('propagate').value === true"> |
|||
<mat-form-field floatLabel="always" class="mat-block" subscriptSizing="dynamic"> |
|||
<mat-label translate>rule-node-config.relation-types-list</mat-label> |
|||
<mat-chip-grid #relationTypesChipList> |
|||
<mat-chip-row |
|||
*ngFor="let key of createAlarmConfigForm.get('relationTypes').value;" |
|||
(removed)="removeKey(key, 'relationTypes')"> |
|||
{{key}} |
|||
<mat-icon matChipRemove>close</mat-icon> |
|||
</mat-chip-row> |
|||
<input matInput type="text" placeholder="{{'rule-node-config.relation-types-list' | translate}}" |
|||
[matChipInputFor]="relationTypesChipList" |
|||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" |
|||
(matChipInputTokenEnd)="addKey($event, 'relationTypes')" |
|||
[matChipInputAddOnBlur]="true"> |
|||
</mat-chip-grid> |
|||
<mat-hint translate>rule-node-config.relation-types-list-hint</mat-hint> |
|||
</mat-form-field> |
|||
</section> |
|||
<mat-checkbox formControlName="propagateToOwner"> |
|||
{{ 'rule-node-config.propagate-to-owner' | translate }} |
|||
</mat-checkbox> |
|||
<mat-checkbox formControlName="propagateToTenant"> |
|||
{{ 'rule-node-config.propagate-to-tenant' | translate }} |
|||
</mat-checkbox> |
|||
</section> |
|||
</section> |
|||
@ -0,0 +1,202 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, EventEmitter, ViewChild } from '@angular/core'; |
|||
import { AppState, getCurrentAuthState, NodeScriptTestService } from '@core/public-api'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
|||
import { MatChipInputEvent } from '@angular/material/chips'; |
|||
import { |
|||
RuleNodeConfiguration, |
|||
RuleNodeConfigurationComponent, |
|||
ScriptLanguage |
|||
} from '@app/shared/models/rule-node.models'; |
|||
import type { JsFuncComponent } from '@app/shared/components/js-func.component'; |
|||
import { AlarmSeverity, alarmSeverityTranslations } from '@app/shared/models/alarm.models'; |
|||
import { DebugRuleNodeEventBody } from '@shared/models/event.models'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-create-alarm-config', |
|||
templateUrl: './create-alarm-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class CreateAlarmConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
@ViewChild('jsFuncComponent', {static: false}) jsFuncComponent: JsFuncComponent; |
|||
@ViewChild('tbelFuncComponent', {static: false}) tbelFuncComponent: JsFuncComponent; |
|||
|
|||
alarmSeverities = Object.keys(AlarmSeverity); |
|||
alarmSeverityTranslationMap = alarmSeverityTranslations; |
|||
createAlarmConfigForm: UntypedFormGroup; |
|||
|
|||
separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; |
|||
|
|||
tbelEnabled = getCurrentAuthState(this.store).tbelEnabled; |
|||
|
|||
scriptLanguage = ScriptLanguage; |
|||
|
|||
changeScript: EventEmitter<void> = new EventEmitter<void>(); |
|||
|
|||
readonly hasScript = true; |
|||
|
|||
readonly testScriptLabel = 'rule-node-config.test-details-function'; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private fb: UntypedFormBuilder, |
|||
private nodeScriptTestService: NodeScriptTestService, |
|||
private translate: TranslateService) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.createAlarmConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.createAlarmConfigForm = this.fb.group({ |
|||
scriptLang: [configuration ? configuration.scriptLang : ScriptLanguage.JS, [Validators.required]], |
|||
alarmDetailsBuildJs: [configuration ? configuration.alarmDetailsBuildJs : null, []], |
|||
alarmDetailsBuildTbel: [configuration ? configuration.alarmDetailsBuildTbel : null, []], |
|||
useMessageAlarmData: [configuration ? configuration.useMessageAlarmData : false, []], |
|||
overwriteAlarmDetails: [configuration ? configuration.overwriteAlarmDetails : false, []], |
|||
alarmType: [configuration ? configuration.alarmType : null, []], |
|||
severity: [configuration ? configuration.severity : null, []], |
|||
propagate: [configuration ? configuration.propagate : false, []], |
|||
relationTypes: [configuration ? configuration.relationTypes : null, []], |
|||
propagateToOwner: [configuration ? configuration.propagateToOwner : false, []], |
|||
propagateToTenant: [configuration ? configuration.propagateToTenant : false, []], |
|||
dynamicSeverity: false |
|||
}); |
|||
|
|||
this.createAlarmConfigForm.get('dynamicSeverity').valueChanges.pipe( |
|||
takeUntilDestroyed(this.destroyRef) |
|||
).subscribe((dynamicSeverity) => { |
|||
if(dynamicSeverity){ |
|||
this.createAlarmConfigForm.get('severity').patchValue('',{emitEvent:false}); |
|||
} else { |
|||
this.createAlarmConfigForm.get('severity').patchValue(this.alarmSeverities[0],{emitEvent:false}); |
|||
} |
|||
}); |
|||
|
|||
} |
|||
|
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['useMessageAlarmData', 'overwriteAlarmDetails', 'scriptLang']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
const useMessageAlarmData: boolean = this.createAlarmConfigForm.get('useMessageAlarmData').value; |
|||
const overwriteAlarmDetails: boolean = this.createAlarmConfigForm.get('overwriteAlarmDetails').value; |
|||
if (useMessageAlarmData) { |
|||
this.createAlarmConfigForm.get('alarmType').setValidators([]); |
|||
this.createAlarmConfigForm.get('severity').setValidators([]); |
|||
} else { |
|||
this.createAlarmConfigForm.get('alarmType').setValidators([Validators.required]); |
|||
this.createAlarmConfigForm.get('severity').setValidators([Validators.required]); |
|||
} |
|||
this.createAlarmConfigForm.get('alarmType').updateValueAndValidity({emitEvent}); |
|||
this.createAlarmConfigForm.get('severity').updateValueAndValidity({emitEvent}); |
|||
|
|||
let scriptLang: ScriptLanguage = this.createAlarmConfigForm.get('scriptLang').value; |
|||
if (scriptLang === ScriptLanguage.TBEL && !this.tbelEnabled) { |
|||
scriptLang = ScriptLanguage.JS; |
|||
this.createAlarmConfigForm.get('scriptLang').patchValue(scriptLang, {emitEvent: false}); |
|||
setTimeout(() => {this.createAlarmConfigForm.updateValueAndValidity({emitEvent: true});}); |
|||
} |
|||
const useAlarmDetailsBuildScript = useMessageAlarmData === false || overwriteAlarmDetails === true; |
|||
this.createAlarmConfigForm.get('alarmDetailsBuildJs') |
|||
.setValidators(useAlarmDetailsBuildScript && scriptLang === ScriptLanguage.JS ? [Validators.required] : []); |
|||
this.createAlarmConfigForm.get('alarmDetailsBuildTbel') |
|||
.setValidators(useAlarmDetailsBuildScript && scriptLang === ScriptLanguage.TBEL ? [Validators.required] : []); |
|||
this.createAlarmConfigForm.get('alarmDetailsBuildJs').updateValueAndValidity({emitEvent}); |
|||
this.createAlarmConfigForm.get('alarmDetailsBuildTbel').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
protected prepareInputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
if (configuration) { |
|||
if (!configuration.scriptLang) { |
|||
configuration.scriptLang = ScriptLanguage.JS; |
|||
} |
|||
} |
|||
return configuration; |
|||
} |
|||
|
|||
testScript(debugEventBody?: DebugRuleNodeEventBody) { |
|||
const scriptLang: ScriptLanguage = this.createAlarmConfigForm.get('scriptLang').value; |
|||
const scriptField = scriptLang === ScriptLanguage.JS ? 'alarmDetailsBuildJs' : 'alarmDetailsBuildTbel'; |
|||
const helpId = scriptLang === ScriptLanguage.JS ? 'rulenode/create_alarm_node_script_fn' : 'rulenode/tbel/create_alarm_node_script_fn'; |
|||
const script: string = this.createAlarmConfigForm.get(scriptField).value; |
|||
this.nodeScriptTestService.testNodeScript( |
|||
script, |
|||
'json', |
|||
this.translate.instant('rule-node-config.details'), |
|||
'Details', |
|||
['msg', 'metadata', 'msgType'], |
|||
this.ruleNodeId, |
|||
helpId, |
|||
scriptLang, |
|||
debugEventBody |
|||
).subscribe((theScript) => { |
|||
if (theScript) { |
|||
this.createAlarmConfigForm.get(scriptField).setValue(theScript); |
|||
this.changeScript.emit(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
removeKey(key: string, keysField: string): void { |
|||
const keys: string[] = this.createAlarmConfigForm.get(keysField).value; |
|||
const index = keys.indexOf(key); |
|||
if (index >= 0) { |
|||
keys.splice(index, 1); |
|||
this.createAlarmConfigForm.get(keysField).setValue(keys, {emitEvent: true}); |
|||
} |
|||
} |
|||
|
|||
addKey(event: MatChipInputEvent, keysField: string): void { |
|||
const input = event.input; |
|||
let value = event.value; |
|||
if ((value || '').trim()) { |
|||
value = value.trim(); |
|||
let keys: string[] = this.createAlarmConfigForm.get(keysField).value; |
|||
if (!keys || keys.indexOf(value) === -1) { |
|||
if (!keys) { |
|||
keys = []; |
|||
} |
|||
keys.push(value); |
|||
this.createAlarmConfigForm.get(keysField).setValue(keys, {emitEvent: true}); |
|||
} |
|||
} |
|||
if (input) { |
|||
input.value = ''; |
|||
} |
|||
} |
|||
|
|||
protected onValidate() { |
|||
const useMessageAlarmData: boolean = this.createAlarmConfigForm.get('useMessageAlarmData').value; |
|||
const overwriteAlarmDetails: boolean = this.createAlarmConfigForm.get('overwriteAlarmDetails').value; |
|||
if (!useMessageAlarmData || overwriteAlarmDetails) { |
|||
const scriptLang: ScriptLanguage = this.createAlarmConfigForm.get('scriptLang').value; |
|||
if (scriptLang === ScriptLanguage.JS) { |
|||
this.jsFuncComponent.validateOnSubmit(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="createRelationConfigForm" class="tb-form-panel no-padding no-border"> |
|||
<div class="tb-form-panel stroked no-padding-bottom"> |
|||
<div class="tb-form-panel-title" translate>rule-node-config.relation-parameters</div> |
|||
<div class="flex flex-col"> |
|||
<mat-form-field class="mat-block" hideRequiredMarker> |
|||
<mat-label translate>relation.direction</mat-label> |
|||
<mat-select required matInput formControlName="direction"> |
|||
<mat-option *ngFor="let type of directionTypes" [value]="type"> |
|||
{{ directionTypeTranslations.get(type) | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<tb-relation-type-autocomplete |
|||
required |
|||
formControlName="relationType"> |
|||
</tb-relation-type-autocomplete> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="tb-form-panel stroked no-padding-bottom"> |
|||
<div class="tb-form-panel-title" translate>rule-node-config.target-entity</div> |
|||
<div class="flex flex-row gap-4"> |
|||
<tb-entity-type-select |
|||
class="flex-1" |
|||
showLabel |
|||
required |
|||
[allowedEntityTypes]="allowedEntityTypes" |
|||
formControlName="entityType"> |
|||
</tb-entity-type-select> |
|||
|
|||
<mat-form-field *ngIf="createRelationConfigForm.get('entityType').value && |
|||
createRelationConfigForm.get('entityType').value !== entityType.TENANT" |
|||
class="mat-block flex-1"> |
|||
<mat-label>{{ entityTypeNamePatternTranslation.get(createRelationConfigForm.get('entityType').value) | translate }}</mat-label> |
|||
<input required matInput formControlName="entityNamePattern"> |
|||
</mat-form-field> |
|||
|
|||
<mat-form-field *ngIf="createRelationConfigForm.get('entityType').value === entityType.DEVICE || |
|||
createRelationConfigForm.get('entityType').value === entityType.ASSET" |
|||
class="mat-block flex-1"> |
|||
<mat-label translate>rule-node-config.profile-name</mat-label> |
|||
<input matInput formControlName="entityTypePattern"> |
|||
</mat-form-field> |
|||
</div> |
|||
|
|||
<tb-example-hint [hintText]="'rule-node-config.kv-map-pattern-hint'" |
|||
*ngIf="createRelationConfigForm.get('entityType').value === entityType.CUSTOMER || |
|||
createRelationConfigForm.get('entityType').value === entityType.DEVICE || |
|||
createRelationConfigForm.get('entityType').value === entityType.ASSET"></tb-example-hint> |
|||
|
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.create-entity-if-not-exists-hint' | translate }}" |
|||
*ngIf="createRelationConfigForm.get('entityType').value === entityType.CUSTOMER || |
|||
createRelationConfigForm.get('entityType').value === entityType.DEVICE || |
|||
createRelationConfigForm.get('entityType').value === entityType.ASSET" |
|||
style="margin-bottom: 18px" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="createEntityIfNotExists"> |
|||
{{ 'rule-node-config.create-entity-if-not-exists' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
</div> |
|||
<section class="tb-form-panel stroked no-padding"> |
|||
<mat-expansion-panel class="tb-settings"> |
|||
<mat-expansion-panel-header style="padding: 16px"> |
|||
<mat-panel-title translate>rule-node-config.advanced-settings</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
<div class="tb-form-panel no-border no-padding-top"> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.remove-current-relations-hint' | translate }}" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="removeCurrentRelations"> |
|||
{{ 'rule-node-config.remove-current-relations' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.change-originator-to-related-entity-hint' | translate }}" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="changeOriginatorToRelatedEntity"> |
|||
{{ 'rule-node-config.change-originator-to-related-entity' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
</div> |
|||
</mat-expansion-panel> |
|||
</section> |
|||
</section> |
|||
@ -0,0 +1,107 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@app/shared/models/rule-node.models'; |
|||
import { EntitySearchDirection } from '@app/shared/models/relation.models'; |
|||
import { EntityType } from '@app/shared/models/entity-type.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-create-relation-config', |
|||
templateUrl: './create-relation-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class CreateRelationConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
directionTypes = Object.keys(EntitySearchDirection); |
|||
directionTypeTranslations = new Map<EntitySearchDirection, string>( |
|||
[ |
|||
[EntitySearchDirection.FROM, 'rule-node-config.search-direction-from'], |
|||
[EntitySearchDirection.TO, 'rule-node-config.search-direction-to'], |
|||
] |
|||
); |
|||
|
|||
entityType = EntityType; |
|||
|
|||
entityTypeNamePatternTranslation = new Map<EntityType, string>( |
|||
[ |
|||
[EntityType.DEVICE, 'rule-node-config.device-name-pattern'], |
|||
[EntityType.ASSET, 'rule-node-config.asset-name-pattern'], |
|||
[EntityType.ENTITY_VIEW, 'rule-node-config.entity-view-name-pattern'], |
|||
[EntityType.CUSTOMER, 'rule-node-config.customer-title-pattern'], |
|||
[EntityType.USER, 'rule-node-config.user-name-pattern'], |
|||
[EntityType.DASHBOARD, 'rule-node-config.dashboard-name-pattern'], |
|||
[EntityType.EDGE, 'rule-node-config.edge-name-pattern'] |
|||
] |
|||
); |
|||
|
|||
allowedEntityTypes = [EntityType.DEVICE, EntityType.ASSET, EntityType.ENTITY_VIEW, EntityType.TENANT, |
|||
EntityType.CUSTOMER, EntityType.USER, EntityType.DASHBOARD, EntityType.EDGE]; |
|||
|
|||
createRelationConfigForm: UntypedFormGroup; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.createRelationConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.createRelationConfigForm = this.fb.group({ |
|||
direction: [configuration ? configuration.direction : null, [Validators.required]], |
|||
entityType: [configuration ? configuration.entityType : null, [Validators.required]], |
|||
entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], |
|||
entityTypePattern: [configuration ? configuration.entityTypePattern : null, []], |
|||
relationType: [configuration ? configuration.relationType : null, [Validators.required]], |
|||
createEntityIfNotExists: [configuration ? configuration.createEntityIfNotExists : false, []], |
|||
removeCurrentRelations: [configuration ? configuration.removeCurrentRelations : false, []], |
|||
changeOriginatorToRelatedEntity: [configuration ? configuration.changeOriginatorToRelatedEntity : false, []] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['entityType', 'createEntityIfNotExists']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
const entityType: EntityType = this.createRelationConfigForm.get('entityType').value; |
|||
if (entityType) { |
|||
this.createRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); |
|||
} else { |
|||
this.createRelationConfigForm.get('entityNamePattern').setValidators([]); |
|||
} |
|||
if (entityType && (entityType === EntityType.DEVICE || entityType === EntityType.ASSET)) { |
|||
const validators = [Validators.pattern(/.*\S.*/)] |
|||
if (this.createRelationConfigForm.get('createEntityIfNotExists').value) { |
|||
validators.push(Validators.required); |
|||
} |
|||
this.createRelationConfigForm.get('entityTypePattern').setValidators(validators); |
|||
} else { |
|||
this.createRelationConfigForm.get('entityTypePattern').setValidators([]); |
|||
} |
|||
this.createRelationConfigForm.get('entityNamePattern').updateValueAndValidity({emitEvent}); |
|||
this.createRelationConfigForm.get('entityTypePattern').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
protected prepareOutputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; |
|||
configuration.entityTypePattern = configuration.entityTypePattern ? configuration.entityTypePattern.trim() : null; |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="deleteAttributesConfigForm" class="tb-form-panel no-border no-padding"> |
|||
<div class="tb-form-panel stroked"> |
|||
<tb-example-hint [hintText]="'rule-node-config.attributes-scope-hint'"> |
|||
</tb-example-hint> |
|||
<div class="tb-form-row no-border no-padding tb-standard-fields"> |
|||
<mat-form-field class="flex"> |
|||
<mat-label>{{ 'rule-node-config.attributes-scope' | translate }}</mat-label> |
|||
<mat-select required |
|||
class="tb-entity-type-select" matInput formControlName="scope"> |
|||
<mat-option *ngFor="let scope of attributeScopes" [value]="scope"> |
|||
{{ telemetryTypeTranslationsMap.get(scope) | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<mat-form-field class="flex"> |
|||
<mat-label>{{ 'rule-node-config.attributes-scope-value' | translate }}</mat-label> |
|||
<input type="text" matInput readonly disabled [ngModel]="deleteAttributesConfigForm.get('scope').value" [ngModelOptions]="{standalone: true}"> |
|||
<button type="button" |
|||
matSuffix |
|||
mat-icon-button |
|||
aria-label="Copy" |
|||
ngxClipboard |
|||
[cbContent]="deleteAttributesConfigForm.get('scope').value" |
|||
matTooltip="{{ 'rule-node-config.attributes-scope-value-copy' | translate }}"> |
|||
<mat-icon aria-hidden="false" |
|||
aria-label="help-icon">content_copy |
|||
</mat-icon> |
|||
</button> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
|
|||
<mat-form-field class="mat-block" subscriptSizing="dynamic"> |
|||
<mat-label>{{ 'rule-node-config.attributes-keys' | translate }}</mat-label> |
|||
<mat-chip-grid formControlName="keys" #attributeChipList> |
|||
<mat-chip-row |
|||
*ngFor="let key of deleteAttributesConfigForm.get('keys').value;" |
|||
(removed)="removeKey(key)"> |
|||
{{key}} |
|||
<mat-icon matChipRemove>close</mat-icon> |
|||
</mat-chip-row> |
|||
<input matInput type="text" |
|||
[matChipInputFor]="attributeChipList" |
|||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" |
|||
(matChipInputTokenEnd)="addKey($event)" |
|||
[matChipInputAddOnBlur]="true"> |
|||
</mat-chip-grid> |
|||
<mat-error *ngIf="deleteAttributesConfigForm.get('keys').hasError('required')">{{ 'rule-node-config.attributes-keys-required' | translate }}</mat-error> |
|||
<mat-hint translate>rule-node-config.general-pattern-hint</mat-hint> |
|||
</mat-form-field> |
|||
|
|||
<section class="tb-form-panel stroked"> |
|||
<mat-expansion-panel class="tb-settings"> |
|||
<mat-expansion-panel-header> |
|||
<mat-panel-title translate>rule-node-config.advanced-settings</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.send-attributes-deleted-notification-hint' | translate }}" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="sendAttributesDeletedNotification"> |
|||
{{ 'rule-node-config.send-attributes-deleted-notification' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.notify-device-on-delete-hint' | translate }}" |
|||
*ngIf="deleteAttributesConfigForm.get('scope').value === attributeScopeMap.SHARED_SCOPE" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="notifyDevice"> |
|||
{{ 'rule-node-config.notify-device' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
</mat-expansion-panel> |
|||
</section> |
|||
</section> |
|||
@ -0,0 +1,91 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, ViewChild } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { MatChipGrid, MatChipInputEvent } from '@angular/material/chips'; |
|||
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
|||
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@app/shared/models/rule-node.models'; |
|||
import { AttributeScope, telemetryTypeTranslations } from '@shared/models/telemetry/telemetry.models'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-delete-attributes-config', |
|||
templateUrl: './delete-attributes-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class DeleteAttributesConfigComponent extends RuleNodeConfigurationComponent { |
|||
@ViewChild('attributeChipList') attributeChipList: MatChipGrid; |
|||
|
|||
deleteAttributesConfigForm: UntypedFormGroup; |
|||
attributeScopeMap = AttributeScope; |
|||
attributeScopes = Object.keys(AttributeScope); |
|||
telemetryTypeTranslationsMap = telemetryTypeTranslations; |
|||
separatorKeysCodes = [ENTER, COMMA, SEMICOLON]; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.deleteAttributesConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.deleteAttributesConfigForm = this.fb.group({ |
|||
scope: [configuration ? configuration.scope : null, [Validators.required]], |
|||
keys: [configuration ? configuration.keys : null, [Validators.required]], |
|||
sendAttributesDeletedNotification: [configuration ? configuration.sendAttributesDeletedNotification : false, []], |
|||
notifyDevice: [configuration ? configuration.notifyDevice : false, []] |
|||
}); |
|||
|
|||
this.deleteAttributesConfigForm.get('scope').valueChanges.pipe( |
|||
takeUntilDestroyed(this.destroyRef) |
|||
).subscribe((value) => { |
|||
if (value !== AttributeScope.SHARED_SCOPE) { |
|||
this.deleteAttributesConfigForm.get('notifyDevice').patchValue(false, {emitEvent: false}); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
removeKey(key: string): void { |
|||
const keys: string[] = this.deleteAttributesConfigForm.get('keys').value; |
|||
const index = keys.indexOf(key); |
|||
if (index >= 0) { |
|||
keys.splice(index, 1); |
|||
this.deleteAttributesConfigForm.get('keys').patchValue(keys, {emitEvent: true}); |
|||
} |
|||
} |
|||
|
|||
addKey(event: MatChipInputEvent): void { |
|||
const input = event.input; |
|||
let value = event.value; |
|||
if ((value || '').trim()) { |
|||
value = value.trim(); |
|||
let keys: string[] = this.deleteAttributesConfigForm.get('keys').value; |
|||
if (!keys || keys.indexOf(value) === -1) { |
|||
if (!keys) { |
|||
keys = []; |
|||
} |
|||
keys.push(value); |
|||
this.deleteAttributesConfigForm.get('keys').patchValue(keys, {emitEvent: true}); |
|||
} |
|||
} |
|||
if (input) { |
|||
input.value = ''; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="deleteRelationConfigForm" class="tb-form-panel no-padding no-border"> |
|||
<div class="tb-form-panel stroked no-padding-bottom"> |
|||
<div class="tb-form-panel-title" translate>rule-node-config.relation-parameters</div> |
|||
<div class="flex flex-col"> |
|||
<mat-form-field class="mat-block" hideRequiredMarker> |
|||
<mat-label translate>relation.direction</mat-label> |
|||
<mat-select required matInput formControlName="direction"> |
|||
<mat-option *ngFor="let type of directionTypes" [value]="type"> |
|||
{{ directionTypeTranslations.get(type) | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<tb-relation-type-autocomplete |
|||
required |
|||
formControlName="relationType"> |
|||
</tb-relation-type-autocomplete> |
|||
</div> |
|||
</div> |
|||
<div class="tb-form-panel stroked"> |
|||
<div tb-hint-tooltip-icon="{{ 'rule-node-config.delete-relation-with-specific-entity-hint' | translate }}" |
|||
class="tb-form-row no-border no-padding"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="deleteForSingleEntity"> |
|||
{{ 'rule-node-config.delete-relation-with-specific-entity' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div *ngIf="deleteRelationConfigForm.get('deleteForSingleEntity').value"> |
|||
<div class="flex flex-row gap-2.5"> |
|||
<tb-entity-type-select |
|||
class="flex-1" |
|||
showLabel |
|||
required |
|||
[allowedEntityTypes]="allowedEntityTypes" |
|||
formControlName="entityType"> |
|||
</tb-entity-type-select> |
|||
<mat-form-field *ngIf="deleteRelationConfigForm.get('entityType').value && deleteRelationConfigForm.get('entityType').value !== entityType.TENANT" |
|||
class="mat-block flex-1"> |
|||
<mat-label>{{ entityTypeNamePatternTranslation.get(deleteRelationConfigForm.get('entityType').value) | translate }}</mat-label> |
|||
<input required matInput formControlName="entityNamePattern"> |
|||
</mat-form-field> |
|||
</div> |
|||
<tb-example-hint *ngIf="deleteRelationConfigForm.get('entityType').value && deleteRelationConfigForm.get('entityType').value !== entityType.TENANT" |
|||
[hintText]="'rule-node-config.kv-map-single-pattern-hint'"></tb-example-hint> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
@ -0,0 +1,101 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { EntityType } from '@app/shared/models/entity-type.models'; |
|||
import { EntitySearchDirection } from '@app/shared/models/relation.models'; |
|||
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@app/shared/models/rule-node.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-delete-relation-config', |
|||
templateUrl: './delete-relation-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class DeleteRelationConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
directionTypes = Object.keys(EntitySearchDirection); |
|||
|
|||
directionTypeTranslations = new Map<EntitySearchDirection, string>( |
|||
[ |
|||
[EntitySearchDirection.FROM, 'rule-node-config.del-relation-direction-from'], |
|||
[EntitySearchDirection.TO, 'rule-node-config.del-relation-direction-to'], |
|||
] |
|||
); |
|||
|
|||
entityTypeNamePatternTranslation = new Map<EntityType, string>( |
|||
[ |
|||
[EntityType.DEVICE, 'rule-node-config.device-name-pattern'], |
|||
[EntityType.ASSET, 'rule-node-config.asset-name-pattern'], |
|||
[EntityType.ENTITY_VIEW, 'rule-node-config.entity-view-name-pattern'], |
|||
[EntityType.CUSTOMER, 'rule-node-config.customer-title-pattern'], |
|||
[EntityType.USER, 'rule-node-config.user-name-pattern'], |
|||
[EntityType.DASHBOARD, 'rule-node-config.dashboard-name-pattern'], |
|||
[EntityType.EDGE, 'rule-node-config.edge-name-pattern'] |
|||
] |
|||
); |
|||
|
|||
entityType = EntityType; |
|||
|
|||
allowedEntityTypes = [EntityType.DEVICE, EntityType.ASSET, EntityType.ENTITY_VIEW, EntityType.TENANT, |
|||
EntityType.CUSTOMER, EntityType.USER, EntityType.DASHBOARD, EntityType.EDGE]; |
|||
|
|||
deleteRelationConfigForm: UntypedFormGroup; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.deleteRelationConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.deleteRelationConfigForm = this.fb.group({ |
|||
deleteForSingleEntity: [configuration ? configuration.deleteForSingleEntity : false, []], |
|||
direction: [configuration ? configuration.direction : null, [Validators.required]], |
|||
entityType: [configuration ? configuration.entityType : null, []], |
|||
entityNamePattern: [configuration ? configuration.entityNamePattern : null, []], |
|||
relationType: [configuration ? configuration.relationType : null, [Validators.required]] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['deleteForSingleEntity', 'entityType']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
const deleteForSingleEntity: boolean = this.deleteRelationConfigForm.get('deleteForSingleEntity').value; |
|||
const entityType: EntityType = this.deleteRelationConfigForm.get('entityType').value; |
|||
if (deleteForSingleEntity) { |
|||
this.deleteRelationConfigForm.get('entityType').setValidators([Validators.required]); |
|||
} else { |
|||
this.deleteRelationConfigForm.get('entityType').setValidators([]); |
|||
} |
|||
if (deleteForSingleEntity && entityType && entityType !== EntityType.TENANT) { |
|||
this.deleteRelationConfigForm.get('entityNamePattern').setValidators([Validators.required, Validators.pattern(/.*\S.*/)]); |
|||
} else { |
|||
this.deleteRelationConfigForm.get('entityNamePattern').setValidators([]); |
|||
} |
|||
this.deleteRelationConfigForm.get('entityType').updateValueAndValidity({emitEvent: false}); |
|||
this.deleteRelationConfigForm.get('entityNamePattern').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
protected prepareOutputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
configuration.entityNamePattern = configuration.entityNamePattern ? configuration.entityNamePattern.trim() : null; |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="deviceProfile" class="tb-form-panel stroked"> |
|||
<div class="tb-form-hint tb-primary-fill" translate>rule-node-config.device-profile-node-hint</div> |
|||
<div tb-hint-tooltip-icon="{{'rule-node-config.persist-alarm-rules-hint' | translate }}" |
|||
class="tb-form-row no-border no-padding slide-toggle"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="persistAlarmRulesState"> |
|||
{{ 'rule-node-config.persist-alarm-rules' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
<div tb-hint-tooltip-icon="{{'rule-node-config.fetch-alarm-rules-hint' | translate }}" |
|||
class="tb-form-row no-border no-padding slide-toggle"> |
|||
<mat-slide-toggle class="mat-slide" formControlName="fetchAlarmRulesStateOnStart"> |
|||
{{ 'rule-node-config.fetch-alarm-rules' | translate }} |
|||
</mat-slide-toggle> |
|||
</div> |
|||
</section> |
|||
@ -0,0 +1,59 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; |
|||
import { RuleNodeConfiguration, RuleNodeConfigurationComponent } from '@shared/models/rule-node.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-device-profile-config', |
|||
templateUrl: './device-profile-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class DeviceProfileConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
deviceProfile: UntypedFormGroup; |
|||
|
|||
constructor(private fb: UntypedFormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.deviceProfile; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.deviceProfile = this.fb.group({ |
|||
persistAlarmRulesState: [configuration ? configuration.persistAlarmRulesState : false], |
|||
fetchAlarmRulesStateOnStart: [configuration ? configuration.fetchAlarmRulesStateOnStart : false] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['persistAlarmRulesState']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
if (this.deviceProfile.get('persistAlarmRulesState').value) { |
|||
this.deviceProfile.get('fetchAlarmRulesStateOnStart').enable({emitEvent: false}); |
|||
} else { |
|||
this.deviceProfile.get('fetchAlarmRulesStateOnStart').setValue(false, {emitEvent: false}); |
|||
this.deviceProfile.get('fetchAlarmRulesStateOnStart').disable({emitEvent: false}); |
|||
} |
|||
this.deviceProfile.get('fetchAlarmRulesStateOnStart').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="deviceState"> |
|||
<mat-form-field class="mat-block" subscriptSizing="dynamic"> |
|||
<mat-label>{{ 'rule-node-config.select-device-connectivity-event' | translate }}</mat-label> |
|||
<mat-select formControlName="event"> |
|||
<mat-option *ngFor="let eventOption of eventOptions" [value]="eventOption"> |
|||
{{ messageTypeNames.get(eventOption) }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
</section> |
|||
@ -0,0 +1,64 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { isDefinedAndNotNull } from '@core/public-api'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { |
|||
MessageType, |
|||
messageTypeNames, |
|||
RuleNodeConfiguration, |
|||
RuleNodeConfigurationComponent |
|||
} from '@shared/models/rule-node.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-device-state-config', |
|||
templateUrl: './device-state-config.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class DeviceStateConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
deviceState: FormGroup; |
|||
|
|||
public messageTypeNames = messageTypeNames; |
|||
public eventOptions: MessageType[] = [ |
|||
MessageType.CONNECT_EVENT, |
|||
MessageType.ACTIVITY_EVENT, |
|||
MessageType.DISCONNECT_EVENT, |
|||
MessageType.INACTIVITY_EVENT |
|||
]; |
|||
|
|||
constructor(private fb: FormBuilder) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): FormGroup { |
|||
return this.deviceState; |
|||
} |
|||
|
|||
protected prepareInputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
return { |
|||
event: isDefinedAndNotNull(configuration?.event) ? configuration.event : MessageType.ACTIVITY_EVENT |
|||
}; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.deviceState = this.fb.group({ |
|||
event: [configuration.event, [Validators.required]] |
|||
}); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2024 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<section [formGroup]="generatorConfigForm" class="tb-form-panel no-border no-padding"> |
|||
<div class="tb-form-panel no-padding-bottom stroked"> |
|||
<div class="tb-form-panel-title" translate>rule-node-config.generation-parameters</div> |
|||
<div class="tb-form-row no-border no-padding tb-standard-fields column-xs"> |
|||
<mat-form-field class="flex"> |
|||
<mat-label translate>rule-node-config.message-count</mat-label> |
|||
<input required type="number" min="0" step="1" matInput formControlName="msgCount"> |
|||
<mat-error *ngIf="generatorConfigForm.get('msgCount').hasError('required')"> |
|||
{{ 'rule-node-config.message-count-required' | translate }} |
|||
</mat-error> |
|||
<mat-error *ngIf="generatorConfigForm.get('msgCount').hasError('min')"> |
|||
{{ 'rule-node-config.min-message-count-message' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<mat-form-field class="flex"> |
|||
<mat-label translate>rule-node-config.generation-frequency-seconds</mat-label> |
|||
<input required type="number" min="1" step="1" matInput formControlName="periodInSeconds"> |
|||
<mat-error *ngIf="generatorConfigForm.get('periodInSeconds').hasError('required')"> |
|||
{{ 'rule-node-config.generation-frequency-required' | translate }} |
|||
</mat-error> |
|||
<mat-error *ngIf="generatorConfigForm.get('periodInSeconds').hasError('min')"> |
|||
{{ 'rule-node-config.min-generation-frequency-message' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="tb-form-panel no-padding-bottom stroked"> |
|||
<div class="tb-form-panel-title" translate>rule-node-config.originator</div> |
|||
<tb-entity-select class="flex-1" |
|||
required="true" |
|||
useAliasEntityTypes="true" |
|||
[allowedEntityTypes]="allowedEntityTypes" |
|||
[additionEntityTypes]="additionEntityTypes" |
|||
formControlName="originator"> |
|||
</tb-entity-select> |
|||
</div> |
|||
<div class="tb-form-panel stroked"> |
|||
<mat-expansion-panel class="tb-settings" expanded> |
|||
<mat-expansion-panel-header> |
|||
<mat-panel-title translate>rule-node-config.generator-function</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
<tb-js-func *ngIf="generatorConfigForm.get('scriptLang').value === scriptLanguage.JS" |
|||
#jsFuncComponent |
|||
formControlName="jsScript" |
|||
functionName="Generate" |
|||
[functionArgs]="['prevMsg', 'prevMetadata', 'prevMsgType']" |
|||
helpId="rulenode/generator_node_script_fn" |
|||
noValidate="true"> |
|||
<tb-toggle-select toolbarPrefixButton formControlName="scriptLang" appearance="fill" *ngIf="tbelEnabled"> |
|||
<tb-toggle-option [value]="scriptLanguage.TBEL"> |
|||
{{ 'rule-node-config.script-lang-tbel' | translate }} |
|||
</tb-toggle-option> |
|||
<tb-toggle-option [value]="scriptLanguage.JS"> |
|||
{{ 'rule-node-config.script-lang-js' | translate }} |
|||
</tb-toggle-option> |
|||
</tb-toggle-select> |
|||
<button toolbarSuffixButton |
|||
mat-icon-button |
|||
matTooltip="{{ testScriptLabel | translate }}" |
|||
matTooltipPosition="above" |
|||
class="tb-mat-32" |
|||
(click)="testScript()"> |
|||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon> |
|||
</button> |
|||
</tb-js-func> |
|||
<tb-js-func *ngIf="generatorConfigForm.get('scriptLang').value === scriptLanguage.TBEL" |
|||
#tbelFuncComponent |
|||
formControlName="tbelScript" |
|||
functionName="Generate" |
|||
[functionArgs]="['prevMsg', 'prevMetadata', 'prevMsgType']" |
|||
[disableUndefinedCheck]="true" |
|||
[scriptLanguage]="scriptLanguage.TBEL" |
|||
helpId="rulenode/tbel/generator_node_script_fn" |
|||
noValidate="true"> |
|||
<tb-toggle-select toolbarPrefixButton formControlName="scriptLang" appearance="fill"> |
|||
<tb-toggle-option [value]="scriptLanguage.TBEL"> |
|||
{{ 'rule-node-config.script-lang-tbel' | translate }} |
|||
</tb-toggle-option> |
|||
<tb-toggle-option [value]="scriptLanguage.JS"> |
|||
{{ 'rule-node-config.script-lang-js' | translate }} |
|||
</tb-toggle-option> |
|||
</tb-toggle-select> |
|||
<button toolbarSuffixButton |
|||
mat-icon-button |
|||
matTooltip="{{ testScriptLabel | translate }}" |
|||
matTooltipPosition="above" |
|||
class="tb-mat-32" |
|||
(click)="testScript()"> |
|||
<mat-icon class="material-icons" color="primary">bug_report</mat-icon> |
|||
</button> |
|||
</tb-js-func> |
|||
<div class="flex flex-row" style="padding-bottom: 16px;"> |
|||
<button mat-button mat-raised-button color="primary" (click)="testScript()"> |
|||
{{ testScriptLabel | translate }} |
|||
</button> |
|||
</div> |
|||
</mat-expansion-panel> |
|||
</div> |
|||
</section> |
|||
@ -0,0 +1,51 @@ |
|||
/** |
|||
* Copyright © 2016-2024 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
:host { |
|||
::ng-deep { |
|||
.mat-button-toggle-group { |
|||
min-width: 120px; |
|||
height: 24px !important; |
|||
.mat-button-toggle { |
|||
font-size: 0; |
|||
.mat-button-toggle-button { |
|||
height: 20px!important; |
|||
line-height: 20px !important; |
|||
border: none !important; |
|||
.mat-button-toggle-label-content { |
|||
font-size: 14px !important; |
|||
line-height: 20px !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.tb-entity-select { |
|||
@media screen and (min-width: 599px) { |
|||
display: flex; |
|||
flex-direction: row; |
|||
gap: 16px; |
|||
} |
|||
tb-entity-type-select { |
|||
flex: 1; |
|||
} |
|||
tb-entity-autocomplete { |
|||
flex: 1; |
|||
mat-form-field { |
|||
width: 100% !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,155 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, EventEmitter, ViewChild } from '@angular/core'; |
|||
import { getCurrentAuthState, isDefinedAndNotNull, NodeScriptTestService } from '@core/public-api'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { |
|||
RuleNodeConfiguration, |
|||
RuleNodeConfigurationComponent, |
|||
ScriptLanguage |
|||
} from '@app/shared/models/rule-node.models'; |
|||
import type { JsFuncComponent } from '@app/shared/components/js-func.component'; |
|||
import { EntityType } from '@app/shared/models/entity-type.models'; |
|||
import { DebugRuleNodeEventBody } from '@shared/models/event.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-action-node-generator-config', |
|||
templateUrl: './generator-config.component.html', |
|||
styleUrls: ['generator-config.component.scss'] |
|||
}) |
|||
export class GeneratorConfigComponent extends RuleNodeConfigurationComponent { |
|||
|
|||
@ViewChild('jsFuncComponent', {static: false}) jsFuncComponent: JsFuncComponent; |
|||
@ViewChild('tbelFuncComponent', {static: false}) tbelFuncComponent: JsFuncComponent; |
|||
|
|||
generatorConfigForm: UntypedFormGroup; |
|||
|
|||
tbelEnabled = getCurrentAuthState(this.store).tbelEnabled; |
|||
|
|||
scriptLanguage = ScriptLanguage; |
|||
|
|||
changeScript: EventEmitter<void> = new EventEmitter<void>(); |
|||
|
|||
allowedEntityTypes = [ |
|||
EntityType.DEVICE, EntityType.ASSET, EntityType.ENTITY_VIEW, EntityType.CUSTOMER, |
|||
EntityType.USER, EntityType.DASHBOARD |
|||
]; |
|||
|
|||
additionEntityTypes = { |
|||
TENANT: this.translate.instant('rule-node-config.current-tenant'), |
|||
RULE_NODE: this.translate.instant('rule-node-config.current-rule-node') |
|||
}; |
|||
|
|||
readonly hasScript = true; |
|||
|
|||
readonly testScriptLabel = 'rule-node-config.test-generator-function'; |
|||
|
|||
constructor(private fb: UntypedFormBuilder, |
|||
private nodeScriptTestService: NodeScriptTestService, |
|||
private translate: TranslateService) { |
|||
super(); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.generatorConfigForm; |
|||
} |
|||
|
|||
protected onConfigurationSet(configuration: RuleNodeConfiguration) { |
|||
this.generatorConfigForm = this.fb.group({ |
|||
msgCount: [configuration ? configuration.msgCount : null, [Validators.required, Validators.min(0)]], |
|||
periodInSeconds: [configuration ? configuration.periodInSeconds : null, [Validators.required, Validators.min(1)]], |
|||
originator: [configuration ? configuration.originator : {id: null, entityType: EntityType.RULE_NODE}, []], |
|||
scriptLang: [configuration ? configuration.scriptLang : ScriptLanguage.JS, [Validators.required]], |
|||
jsScript: [configuration ? configuration.jsScript : null, []], |
|||
tbelScript: [configuration ? configuration.tbelScript : null, []] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['scriptLang']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
let scriptLang: ScriptLanguage = this.generatorConfigForm.get('scriptLang').value; |
|||
if (scriptLang === ScriptLanguage.TBEL && !this.tbelEnabled) { |
|||
scriptLang = ScriptLanguage.JS; |
|||
this.generatorConfigForm.get('scriptLang').patchValue(scriptLang, {emitEvent: false}); |
|||
setTimeout(() => {this.generatorConfigForm.updateValueAndValidity({emitEvent: true});}); |
|||
} |
|||
this.generatorConfigForm.get('jsScript').setValidators(scriptLang === ScriptLanguage.JS ? [Validators.required] : []); |
|||
this.generatorConfigForm.get('jsScript').updateValueAndValidity({emitEvent}); |
|||
this.generatorConfigForm.get('tbelScript').setValidators(scriptLang === ScriptLanguage.TBEL ? [Validators.required] : []); |
|||
this.generatorConfigForm.get('tbelScript').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
protected prepareInputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
return { |
|||
msgCount: isDefinedAndNotNull(configuration?.msgCount) ? configuration?.msgCount : 0, |
|||
periodInSeconds: isDefinedAndNotNull(configuration?.periodInSeconds) ? configuration?.periodInSeconds : 1, |
|||
originator: { |
|||
id: isDefinedAndNotNull(configuration?.originatorId) ? configuration?.originatorId : null, |
|||
entityType: isDefinedAndNotNull(configuration?.originatorType) ? configuration?.originatorType : EntityType.RULE_NODE |
|||
}, |
|||
scriptLang: isDefinedAndNotNull(configuration?.scriptLang) ? configuration?.scriptLang : ScriptLanguage.JS, |
|||
tbelScript: isDefinedAndNotNull(configuration?.tbelScript) ? configuration?.tbelScript : null, |
|||
jsScript: isDefinedAndNotNull(configuration?.jsScript) ? configuration?.jsScript : null, |
|||
}; |
|||
} |
|||
|
|||
protected prepareOutputConfig(configuration: RuleNodeConfiguration): RuleNodeConfiguration { |
|||
if (configuration.originator) { |
|||
configuration.originatorId = configuration.originator.id; |
|||
configuration.originatorType = configuration.originator.entityType; |
|||
} else { |
|||
configuration.originatorId = null; |
|||
configuration.originatorType = null; |
|||
} |
|||
delete configuration.originator; |
|||
return configuration; |
|||
} |
|||
|
|||
testScript(debugEventBody?: DebugRuleNodeEventBody) { |
|||
const scriptLang: ScriptLanguage = this.generatorConfigForm.get('scriptLang').value; |
|||
const scriptField = scriptLang === ScriptLanguage.JS ? 'jsScript' : 'tbelScript'; |
|||
const helpId = scriptLang === ScriptLanguage.JS ? 'rulenode/generator_node_script_fn' : 'rulenode/tbel/generator_node_script_fn'; |
|||
const script: string = this.generatorConfigForm.get(scriptField).value; |
|||
this.nodeScriptTestService.testNodeScript( |
|||
script, |
|||
'generate', |
|||
this.translate.instant('rule-node-config.generator'), |
|||
'Generate', |
|||
['prevMsg', 'prevMetadata', 'prevMsgType'], |
|||
this.ruleNodeId, |
|||
helpId, |
|||
scriptLang, |
|||
debugEventBody |
|||
).subscribe((theScript) => { |
|||
if (theScript) { |
|||
this.generatorConfigForm.get(scriptField).setValue(theScript); |
|||
this.changeScript.emit(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
protected onValidate() { |
|||
const scriptLang: ScriptLanguage = this.generatorConfigForm.get('scriptLang').value; |
|||
if (scriptLang === ScriptLanguage.JS) { |
|||
this.jsFuncComponent.validateOnSubmit(); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue