Merge branch 'develop/3.5.2' into feature/widget-bundles
This commit is contained in:
		
						commit
						9a0b0fbefa
					
				@ -42,6 +42,7 @@ import {
 | 
			
		||||
  EntityCountCmd,
 | 
			
		||||
  EntityDataCmd,
 | 
			
		||||
  IndexedSubscriptionData,
 | 
			
		||||
  NOT_SUPPORTED,
 | 
			
		||||
  SubscriptionData,
 | 
			
		||||
  TelemetrySubscriber
 | 
			
		||||
} from '@shared/models/telemetry/telemetry.models';
 | 
			
		||||
@ -786,7 +787,7 @@ export class EntityDataSubscription {
 | 
			
		||||
  private reportNotSupported(keys: AggKey[], isUpdate: boolean) {
 | 
			
		||||
    const indexedData: IndexedSubscriptionData = [];
 | 
			
		||||
    for (const key of keys) {
 | 
			
		||||
      indexedData[key.id] = [[0, 'Not supported!']];
 | 
			
		||||
      indexedData[key.id] = [[0, NOT_SUPPORTED]];
 | 
			
		||||
    }
 | 
			
		||||
    for (let dataIndex = 0; dataIndex < this.pageData.data.length; dataIndex++) {
 | 
			
		||||
      this.onIndexedData(indexedData, dataIndex, true,
 | 
			
		||||
 | 
			
		||||
@ -81,6 +81,7 @@ import { distinct, filter, map, switchMap, takeUntil } from 'rxjs/operators';
 | 
			
		||||
import { AlarmDataListener } from '@core/api/alarm-data.service';
 | 
			
		||||
import { RpcStatus } from '@shared/models/rpc.models';
 | 
			
		||||
import { EventEmitter } from '@angular/core';
 | 
			
		||||
import { NOT_SUPPORTED } from '@shared/models/telemetry/telemetry.models';
 | 
			
		||||
 | 
			
		||||
const moment = moment_;
 | 
			
		||||
 | 
			
		||||
@ -1541,7 +1542,7 @@ export class WidgetSubscription implements IWidgetSubscription {
 | 
			
		||||
      } else if (prevData && prevData[0] && prevData[0].length > 1 && data.data.length > 0) {
 | 
			
		||||
        const prevTs = prevData[0][0];
 | 
			
		||||
        const prevValue = prevData[0][1];
 | 
			
		||||
        if (prevTs === data.data[0][0] && prevValue === data.data[0][1]) {
 | 
			
		||||
        if (prevTs === data.data[0][0] && prevValue === data.data[0][1] && data.data[0][1] !== NOT_SUPPORTED) {
 | 
			
		||||
          update = false;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -161,12 +161,14 @@ import { HasDirtyFlag } from '@core/guards/confirm-on-exit.guard';
 | 
			
		||||
})
 | 
			
		||||
export class DashboardPageComponent extends PageComponent implements IDashboardController, HasDirtyFlag, OnInit, AfterViewInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  private forcePristine = false;
 | 
			
		||||
 | 
			
		||||
  get isDirty(): boolean {
 | 
			
		||||
    return this.isEdit;
 | 
			
		||||
    return this.isEdit && !this.forcePristine;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set isDirty(value: boolean) {
 | 
			
		||||
 | 
			
		||||
    this.forcePristine = !value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  authState: AuthState = getCurrentAuthState(this.store);
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,11 @@
 | 
			
		||||
          (click)="editAssetProfile($event)">
 | 
			
		||||
    <mat-icon class="material-icons">edit</mat-icon>
 | 
			
		||||
  </button>
 | 
			
		||||
  <button mat-button color="primary" matSuffix
 | 
			
		||||
          (click)="createAssetProfile($event, '')"
 | 
			
		||||
          *ngIf="!selectAssetProfileFormGroup.get('assetProfile').value && !disabled && addNewProfile">
 | 
			
		||||
    <span style="white-space: nowrap">{{ 'notification.create-new' | translate }}</span>
 | 
			
		||||
  </button>
 | 
			
		||||
  <mat-autocomplete
 | 
			
		||||
    class="tb-autocomplete"
 | 
			
		||||
    (closed)="onPanelClosed()"
 | 
			
		||||
 | 
			
		||||
@ -19,3 +19,9 @@
 | 
			
		||||
    color: inherit;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:host ::ng-deep {
 | 
			
		||||
  .mat-mdc-form-field-icon-suffix {
 | 
			
		||||
    display: flex;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,7 @@ import { AssetProfile, AssetProfileInfo } from '@shared/models/asset.models';
 | 
			
		||||
import { AssetProfileService } from '@core/http/asset-profile.service';
 | 
			
		||||
import { AssetProfileDialogComponent, AssetProfileDialogData } from './asset-profile-dialog.component';
 | 
			
		||||
import { SubscriptSizing } from '@angular/material/form-field';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-asset-profile-autocomplete',
 | 
			
		||||
@ -84,14 +85,9 @@ export class AssetProfileAutocompleteComponent implements ControlValueAccessor,
 | 
			
		||||
  @Input()
 | 
			
		||||
  showDetailsPageLink = false;
 | 
			
		||||
 | 
			
		||||
  private requiredValue: boolean;
 | 
			
		||||
  get required(): boolean {
 | 
			
		||||
    return this.requiredValue;
 | 
			
		||||
  }
 | 
			
		||||
  @Input()
 | 
			
		||||
  set required(value: boolean) {
 | 
			
		||||
    this.requiredValue = coerceBooleanProperty(value);
 | 
			
		||||
  }
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  required = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
 | 
			
		||||
@ -45,7 +45,7 @@
 | 
			
		||||
  </button>
 | 
			
		||||
  <button mat-button color="primary" matSuffix
 | 
			
		||||
          (click)="createDeviceProfile($event, '')"
 | 
			
		||||
          *ngIf="!selectDeviceProfileFormGroup.get('deviceProfile').value && !disabled && addNewProfile && showCreateNewButton">
 | 
			
		||||
          *ngIf="!selectDeviceProfileFormGroup.get('deviceProfile').value && !disabled && addNewProfile">
 | 
			
		||||
    <span style="white-space: nowrap">{{ 'notification.create-new' | translate }}</span>
 | 
			
		||||
  </button>
 | 
			
		||||
  <mat-autocomplete
 | 
			
		||||
 | 
			
		||||
@ -88,10 +88,6 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  addNewProfile = true;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  showCreateNewButton = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  showDetailsPageLink = false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -70,7 +70,7 @@
 | 
			
		||||
                          [indeterminate]="alarmsDatasource.selection.hasValue() && !(alarmsDatasource.isAllSelected() | async)">
 | 
			
		||||
            </mat-checkbox>
 | 
			
		||||
          </mat-header-cell>
 | 
			
		||||
          <mat-cell *matCellDef="let alarm">
 | 
			
		||||
          <mat-cell *matCellDef="let alarm; let row = index" [style]="rowStyle(alarm, row)">
 | 
			
		||||
            <mat-checkbox (click)="$event.stopPropagation();"
 | 
			
		||||
                          (change)="$event ? alarmsDatasource.toggleSelection(alarm) : null"
 | 
			
		||||
                          [checked]="alarmsDatasource.isSelected(alarm)">
 | 
			
		||||
@ -122,7 +122,7 @@
 | 
			
		||||
                                                                maxWidth: (alarmsDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                width: (alarmsDatasource.countCellButtonAction * 48) + 'px' }">
 | 
			
		||||
          </mat-header-cell>
 | 
			
		||||
          <mat-cell *matCellDef="let alarm" [ngStyle.gt-md]="{ minWidth: (alarmsDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
          <mat-cell *matCellDef="let alarm; let row = index" [style]="rowStyle(alarm, row)" [ngStyle.gt-md]="{ minWidth: (alarmsDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                               maxWidth: (alarmsDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                               width: (alarmsDatasource.countCellButtonAction * 48) + 'px' }">
 | 
			
		||||
            <div [fxHide]="showCellActionsMenu" fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@
 | 
			
		||||
                                                                maxWidth: (entityDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                width: (entityDatasource.countCellButtonAction * 48) + 'px' }">
 | 
			
		||||
          </mat-header-cell>
 | 
			
		||||
          <mat-cell *matCellDef="let entity" [ngStyle.gt-md]="{ minWidth: (entityDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
          <mat-cell *matCellDef="let entity; let row = index" [style]="rowStyle(entity, row)" [ngStyle.gt-md]="{ minWidth: (entityDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                maxWidth: (entityDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                width: (entityDatasource.countCellButtonAction * 48) + 'px' }">
 | 
			
		||||
            <div [fxHide]="showCellActionsMenu && entityDatasource.countCellButtonAction !== 1" fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
 | 
			
		||||
 | 
			
		||||
@ -452,7 +452,7 @@ export function constructTableCssString(widgetConfig: WidgetConfig): string {
 | 
			
		||||
    '.mat-mdc-table .mat-mdc-row .mat-mdc-cell.mat-mdc-table-sticky, .mat-mdc-table .mat-mdc-header-cell.mat-mdc-table-sticky {\n' +
 | 
			
		||||
    'background-color: ' + origBackgroundColor + ';\n' +
 | 
			
		||||
    '}\n' +
 | 
			
		||||
    '.mat-mdc-table .mat-mdc-cell {\n' +
 | 
			
		||||
    '.mat-mdc-table .mat-mdc-row {\n' +
 | 
			
		||||
    'color: ' + mdDark + ';\n' +
 | 
			
		||||
    'background-color: rgba(0, 0, 0, 0);\n' +
 | 
			
		||||
    '}\n' +
 | 
			
		||||
 | 
			
		||||
@ -64,7 +64,7 @@
 | 
			
		||||
                                                                      maxWidth: (source.timeseriesDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                      width: (source.timeseriesDatasource.countCellButtonAction * 48) + 'px' }">
 | 
			
		||||
                </mat-header-cell>
 | 
			
		||||
                <mat-cell *matCellDef="let row" [ngStyle.gt-md]="{ minWidth: (source.timeseriesDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                <mat-cell *matCellDef="let entity; let row = index" [style]="rowStyle(source, entity, row)" [ngStyle.gt-md]="{ minWidth: (source.timeseriesDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                   maxWidth: (source.timeseriesDatasource.countCellButtonAction * 48) + 'px',
 | 
			
		||||
                                                                   width: (source.timeseriesDatasource.countCellButtonAction * 48) + 'px' }">
 | 
			
		||||
                  <div [fxHide]="showCellActionsMenu && source.timeseriesDatasource.countCellButtonAction !== 1" fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
 | 
			
		||||
@ -74,22 +74,22 @@
 | 
			
		||||
                              mat-icon-button [disabled]="isLoading$ | async"
 | 
			
		||||
                              matTooltip="{{ actionDescriptor.displayName }}"
 | 
			
		||||
                              matTooltipPosition="above"
 | 
			
		||||
                              (click)="onActionButtonClick($event, row, actionDescriptor)">
 | 
			
		||||
                              (click)="onActionButtonClick($event, entity, actionDescriptor)">
 | 
			
		||||
                        <mat-icon>{{actionDescriptor.icon}}</mat-icon>
 | 
			
		||||
                      </button>
 | 
			
		||||
                    </ng-container>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div fxHide [fxShow.lt-lg]="showCellActionsMenu && source.timeseriesDatasource.countCellButtonAction !== 1" *ngIf="row.hasActions">
 | 
			
		||||
                  <div fxHide [fxShow.lt-lg]="showCellActionsMenu && source.timeseriesDatasource.countCellButtonAction !== 1" *ngIf="entity.hasActions">
 | 
			
		||||
                    <button mat-icon-button
 | 
			
		||||
                            (click)="$event.stopPropagation(); ctx.detectChanges();"
 | 
			
		||||
                            [matMenuTriggerFor]="cellActionsMenu">
 | 
			
		||||
                      <mat-icon class="material-icons">more_vert</mat-icon>
 | 
			
		||||
                    </button>
 | 
			
		||||
                    <mat-menu #cellActionsMenu="matMenu" xPosition="before">
 | 
			
		||||
                      <ng-container *ngFor="let actionDescriptor of row.actionCellButtons; trackBy: trackByActionCellDescriptionId">
 | 
			
		||||
                      <ng-container *ngFor="let actionDescriptor of entity.actionCellButtons; trackBy: trackByActionCellDescriptionId">
 | 
			
		||||
                        <button mat-menu-item *ngIf="actionDescriptor.icon"
 | 
			
		||||
                                [disabled]="isLoading$ | async"
 | 
			
		||||
                                (click)="onActionButtonClick($event, row, actionDescriptor)">
 | 
			
		||||
                                (click)="onActionButtonClick($event, entity, actionDescriptor)">
 | 
			
		||||
                          <mat-icon>{{actionDescriptor.icon}}</mat-icon>
 | 
			
		||||
                          <span>{{ actionDescriptor.displayName }}</span>
 | 
			
		||||
                        </button>
 | 
			
		||||
 | 
			
		||||
@ -146,11 +146,8 @@ export class DeviceWizardDialogComponent extends DialogComponent<DeviceWizardDia
 | 
			
		||||
        overwriteActivityTime: this.deviceWizardFormGroup.get('overwriteActivityTime').value,
 | 
			
		||||
        description: this.deviceWizardFormGroup.get('description').value
 | 
			
		||||
      },
 | 
			
		||||
      customerId: null
 | 
			
		||||
      customerId: this.deviceWizardFormGroup.get('customerId').value
 | 
			
		||||
    };
 | 
			
		||||
    if (this.deviceWizardFormGroup.get('customerId').value) {
 | 
			
		||||
      device.customerId = new CustomerId(this.deviceWizardFormGroup.get('customerId').value);
 | 
			
		||||
    }
 | 
			
		||||
    if (this.addDeviceWizardStepper.steps.last.completed || this.addDeviceWizardStepper.selectedIndex > 0) {
 | 
			
		||||
      return this.deviceService.saveDeviceWithCredentials(deepTrim(device), deepTrim(this.credentialsFormGroup.value.credential)).pipe(
 | 
			
		||||
        catchError((e: HttpErrorResponse) => {
 | 
			
		||||
 | 
			
		||||
@ -86,13 +86,6 @@
 | 
			
		||||
          {{ 'asset.name-max-length' | translate }}
 | 
			
		||||
        </mat-error>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
      <tb-asset-profile-autocomplete
 | 
			
		||||
        [selectDefaultProfile]="isAdd"
 | 
			
		||||
        required
 | 
			
		||||
        formControlName="assetProfileId"
 | 
			
		||||
        [showDetailsPageLink]="true"
 | 
			
		||||
        (assetProfileUpdated)="onAssetProfileUpdated()">
 | 
			
		||||
      </tb-asset-profile-autocomplete>
 | 
			
		||||
      <mat-form-field class="mat-block">
 | 
			
		||||
        <mat-label translate>asset.label</mat-label>
 | 
			
		||||
        <input matInput formControlName="label">
 | 
			
		||||
@ -100,6 +93,20 @@
 | 
			
		||||
          {{ 'asset.label-max-length' | translate }}
 | 
			
		||||
        </mat-error>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
      <tb-asset-profile-autocomplete
 | 
			
		||||
        [selectDefaultProfile]="isAdd"
 | 
			
		||||
        required
 | 
			
		||||
        formControlName="assetProfileId"
 | 
			
		||||
        [showDetailsPageLink]="true"
 | 
			
		||||
        (assetProfileUpdated)="onAssetProfileUpdated()">
 | 
			
		||||
      </tb-asset-profile-autocomplete>
 | 
			
		||||
      <tb-entity-autocomplete
 | 
			
		||||
        *ngIf="isAdd"
 | 
			
		||||
        useFullEntityId
 | 
			
		||||
        formControlName="customerId"
 | 
			
		||||
        labelText="asset.assign-to-customer"
 | 
			
		||||
        [entityType]="entityType.CUSTOMER">
 | 
			
		||||
      </tb-entity-autocomplete>
 | 
			
		||||
      <div formGroupName="additionalInfo">
 | 
			
		||||
        <mat-form-field class="mat-block">
 | 
			
		||||
          <mat-label translate>asset.description</mat-label>
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,7 @@ export class AssetComponent extends EntityComponent<AssetInfo> {
 | 
			
		||||
        name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]],
 | 
			
		||||
        assetProfileId: [entity ? entity.assetProfileId : null, [Validators.required]],
 | 
			
		||||
        label: [entity ? entity.label : '', Validators.maxLength(255)],
 | 
			
		||||
        customerId: [entity ? entity.customerId : ''],
 | 
			
		||||
        additionalInfo: this.fb.group(
 | 
			
		||||
          {
 | 
			
		||||
            description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''],
 | 
			
		||||
@ -82,6 +83,7 @@ export class AssetComponent extends EntityComponent<AssetInfo> {
 | 
			
		||||
    this.entityForm.patchValue({name: entity.name});
 | 
			
		||||
    this.entityForm.patchValue({assetProfileId: entity.assetProfileId});
 | 
			
		||||
    this.entityForm.patchValue({label: entity.label});
 | 
			
		||||
    this.entityForm.patchValue({customerId: entity.customerId});
 | 
			
		||||
    this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,16 +29,12 @@
 | 
			
		||||
  <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
 | 
			
		||||
  </mat-progress-bar>
 | 
			
		||||
  <div mat-dialog-content>
 | 
			
		||||
    <fieldset [disabled]="isLoading$ | async">
 | 
			
		||||
      <tb-rule-node #tbRuleNode
 | 
			
		||||
        [ruleNode]="ruleNode"
 | 
			
		||||
        [ruleChainId]="ruleChainId"
 | 
			
		||||
        [ruleChainType]="ruleChainType"
 | 
			
		||||
        [isEdit]="true"
 | 
			
		||||
        [isAdd]="true"
 | 
			
		||||
        [isReadOnly]="false">
 | 
			
		||||
      </tb-rule-node>
 | 
			
		||||
    </fieldset>
 | 
			
		||||
    <tb-rule-node #tbRuleNode
 | 
			
		||||
                  [ruleNode]="ruleNode"
 | 
			
		||||
                  [ruleChainId]="ruleChainId"
 | 
			
		||||
                  [ruleChainType]="ruleChainType"
 | 
			
		||||
                  isAdd>
 | 
			
		||||
    </tb-rule-node>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div mat-dialog-actions fxLayoutAlign="end center">
 | 
			
		||||
    <button mat-button color="primary"
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
 */
 | 
			
		||||
:host {
 | 
			
		||||
  display: block;
 | 
			
		||||
  margin-bottom: 16px;
 | 
			
		||||
 | 
			
		||||
  tb-json-object-edit.tb-rule-node-configuration-json {
 | 
			
		||||
    display: block;
 | 
			
		||||
    height: 300px;
 | 
			
		||||
 | 
			
		||||
@ -165,6 +165,9 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
 | 
			
		||||
    } else {
 | 
			
		||||
      this.ruleNodeConfigFormGroup.enable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
    if (this.definedConfigComponent) {
 | 
			
		||||
      this.definedConfigComponent.disabled = this.disabled;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  writeValue(value: RuleNodeConfiguration): void {
 | 
			
		||||
@ -222,6 +225,7 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On
 | 
			
		||||
      this.definedConfigComponent.ruleChainId = this.ruleChainId;
 | 
			
		||||
      this.definedConfigComponent.ruleChainType = this.ruleChainType;
 | 
			
		||||
      this.definedConfigComponent.configuration = this.configuration;
 | 
			
		||||
      this.definedConfigComponent.disabled = this.disabled;
 | 
			
		||||
      this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => {
 | 
			
		||||
        this.updateModel(configuration);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@ -22,44 +22,40 @@
 | 
			
		||||
  </button>
 | 
			
		||||
</div>
 | 
			
		||||
<form [formGroup]="ruleNodeFormGroup" class="mat-padding">
 | 
			
		||||
  <fieldset [disabled]="(isLoading$ | async) || !isEdit || isReadOnly">
 | 
			
		||||
    <section>
 | 
			
		||||
      <section class="title-row">
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>rulenode.name</mat-label>
 | 
			
		||||
          <input matInput formControlName="name" required>
 | 
			
		||||
          <mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('required')
 | 
			
		||||
  <section class="title-row">
 | 
			
		||||
    <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
      <mat-label translate>rulenode.name</mat-label>
 | 
			
		||||
      <input matInput formControlName="name" required>
 | 
			
		||||
      <mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('required')
 | 
			
		||||
                         || ruleNodeFormGroup.get('name').hasError('pattern')">
 | 
			
		||||
            {{ 'rulenode.name-required' | translate }}
 | 
			
		||||
          </mat-error>
 | 
			
		||||
          <mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('maxlength')">
 | 
			
		||||
            {{ 'rulenode.name-max-length' | translate }}
 | 
			
		||||
          </mat-error>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <section class="node-setting">
 | 
			
		||||
          <mat-slide-toggle formControlName="debugMode">
 | 
			
		||||
            {{ 'rulenode.debug-mode' | translate }}
 | 
			
		||||
          </mat-slide-toggle>
 | 
			
		||||
          <mat-slide-toggle *ngIf="isSingletonEditAllowed()" formControlName="singletonMode">
 | 
			
		||||
            {{ 'rulenode.singleton-mode' | translate }}
 | 
			
		||||
          </mat-slide-toggle >
 | 
			
		||||
        </section>
 | 
			
		||||
      </section>
 | 
			
		||||
      <tb-rule-node-config #ruleNodeConfigComponent
 | 
			
		||||
        formControlName="configuration"
 | 
			
		||||
        [ruleNodeId]="ruleNode.ruleNodeId?.id"
 | 
			
		||||
        [ruleChainId]="ruleChainId"
 | 
			
		||||
        [ruleChainType]="ruleChainType"
 | 
			
		||||
        [nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition"
 | 
			
		||||
        (initRuleNode)="initRuleNode.emit($event)"
 | 
			
		||||
        (changeScript)="changeScript.emit($event)">
 | 
			
		||||
      </tb-rule-node-config>
 | 
			
		||||
      <div formGroupName="additionalInfo" fxLayout="column" class="description-block">
 | 
			
		||||
        <mat-form-field class="mat-block">
 | 
			
		||||
          <mat-label translate>rulenode.rule-node-description</mat-label>
 | 
			
		||||
          <textarea matInput formControlName="description" rows="1"></textarea>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </div>
 | 
			
		||||
        {{ 'rulenode.name-required' | translate }}
 | 
			
		||||
      </mat-error>
 | 
			
		||||
      <mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('maxlength')">
 | 
			
		||||
        {{ 'rulenode.name-max-length' | translate }}
 | 
			
		||||
      </mat-error>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
    <section class="node-setting">
 | 
			
		||||
      <mat-slide-toggle formControlName="debugMode">
 | 
			
		||||
        {{ 'rulenode.debug-mode' | translate }}
 | 
			
		||||
      </mat-slide-toggle>
 | 
			
		||||
      <mat-slide-toggle *ngIf="isSingletonEditAllowed()" formControlName="singletonMode">
 | 
			
		||||
        {{ 'rulenode.singleton-mode' | translate }}
 | 
			
		||||
      </mat-slide-toggle>
 | 
			
		||||
    </section>
 | 
			
		||||
  </fieldset>
 | 
			
		||||
  </section>
 | 
			
		||||
  <tb-rule-node-config #ruleNodeConfigComponent
 | 
			
		||||
                       formControlName="configuration"
 | 
			
		||||
                       [ruleNodeId]="ruleNode.ruleNodeId?.id"
 | 
			
		||||
                       [ruleChainId]="ruleChainId"
 | 
			
		||||
                       [ruleChainType]="ruleChainType"
 | 
			
		||||
                       [nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition"
 | 
			
		||||
                       (initRuleNode)="initRuleNode.emit($event)"
 | 
			
		||||
                       (changeScript)="changeScript.emit($event)">
 | 
			
		||||
  </tb-rule-node-config>
 | 
			
		||||
  <div formGroupName="additionalInfo" fxLayout="column" class="description-block">
 | 
			
		||||
    <mat-form-field class="mat-block">
 | 
			
		||||
      <mat-label translate>rulenode.rule-node-description</mat-label>
 | 
			
		||||
      <textarea matInput formControlName="description" rows="1"></textarea>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
  </div>
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
@ -22,11 +22,11 @@ import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms
 | 
			
		||||
import { FcRuleNode, RuleNodeType } from '@shared/models/rule-node.models';
 | 
			
		||||
import { EntityType } from '@shared/models/entity-type.models';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { RuleChainService } from '@core/http/rule-chain.service';
 | 
			
		||||
import { RuleNodeConfigComponent } from './rule-node-config.component';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { RuleChainType } from '@app/shared/models/rule-chain.models';
 | 
			
		||||
import { ComponentClusteringMode } from '@shared/models/component-descriptor.models';
 | 
			
		||||
import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-rule-node',
 | 
			
		||||
@ -47,12 +47,11 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
 | 
			
		||||
  ruleChainType: RuleChainType;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  isEdit: boolean;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  isReadOnly: boolean;
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  disabled = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  isAdd = false;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
@ -70,7 +69,6 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private fb: UntypedFormBuilder,
 | 
			
		||||
              private ruleChainService: RuleChainService,
 | 
			
		||||
              private router: Router) {
 | 
			
		||||
    super(store);
 | 
			
		||||
    this.ruleNodeFormGroup = this.fb.group({});
 | 
			
		||||
@ -99,6 +97,9 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
 | 
			
		||||
    } else {
 | 
			
		||||
      this.ruleNodeFormGroup = this.fb.group({});
 | 
			
		||||
    }
 | 
			
		||||
    if (this.disabled) {
 | 
			
		||||
      this.ruleNodeFormGroup.disable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateRuleNode() {
 | 
			
		||||
@ -108,6 +109,9 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    if (this.disabled) {
 | 
			
		||||
      this.ruleNodeFormGroup.disable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnChanges(changes: SimpleChanges): void {
 | 
			
		||||
 | 
			
		||||
@ -110,8 +110,6 @@
 | 
			
		||||
                              [ruleNode]="editingRuleNode"
 | 
			
		||||
                              [ruleChainId]="ruleChain.id?.id"
 | 
			
		||||
                              [ruleChainType]="ruleChainType"
 | 
			
		||||
                              [isEdit]="true"
 | 
			
		||||
                              [isReadOnly]="false"
 | 
			
		||||
                              (initRuleNode)="onRuleNodeInit()"
 | 
			
		||||
                              (changeScript)="switchToFirstTab()">
 | 
			
		||||
                </tb-rule-node>
 | 
			
		||||
 | 
			
		||||
@ -74,6 +74,7 @@ export interface IRuleNodeConfigurationComponent {
 | 
			
		||||
  ruleNodeId: string;
 | 
			
		||||
  ruleChainId: string;
 | 
			
		||||
  hasScript: boolean;
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
  testScriptLabel?: string;
 | 
			
		||||
  changeScript?: EventEmitter<void>;
 | 
			
		||||
  ruleChainType: RuleChainType;
 | 
			
		||||
@ -101,6 +102,14 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple
 | 
			
		||||
 | 
			
		||||
  private configurationSet = false;
 | 
			
		||||
 | 
			
		||||
  set disabled(value: boolean) {
 | 
			
		||||
    if (value) {
 | 
			
		||||
      this.configForm().disable({emitEvent: false});
 | 
			
		||||
    } else {
 | 
			
		||||
      this.configForm().enable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  set configuration(value: RuleNodeConfiguration) {
 | 
			
		||||
    this.configurationValue = value;
 | 
			
		||||
    if (!this.configurationSet) {
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,8 @@ import { isUndefined } from '@core/utils';
 | 
			
		||||
import { CmdWrapper, WsSubscriber } from '@shared/models/websocket/websocket.models';
 | 
			
		||||
import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service';
 | 
			
		||||
 | 
			
		||||
export const NOT_SUPPORTED = 'Not supported!';
 | 
			
		||||
 | 
			
		||||
export enum DataKeyType {
 | 
			
		||||
  timeseries = 'timeseries',
 | 
			
		||||
  attribute = 'attribute',
 | 
			
		||||
 | 
			
		||||
@ -692,6 +692,21 @@ mat-label {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tb-table-widget {
 | 
			
		||||
    .mat-mdc-table {
 | 
			
		||||
      .mat-mdc-cell {
 | 
			
		||||
        background: inherit;
 | 
			
		||||
        color: inherit;
 | 
			
		||||
        font-size: inherit;
 | 
			
		||||
        font-family: inherit;
 | 
			
		||||
        font-weight: inherit;
 | 
			
		||||
        line-height: inherit;
 | 
			
		||||
        letter-spacing: inherit;
 | 
			
		||||
        text-transform: inherit;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .mat-mdc-footer-row::after, .mat-mdc-header-row::after, .mat-mdc-row::after {
 | 
			
		||||
    content: none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user