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