Add mobile dashboard to alarm rules
This commit is contained in:
parent
5afc39eb60
commit
b4566a93fd
@ -16,6 +16,7 @@
|
|||||||
package org.thingsboard.server.common.data.device.profile;
|
package org.thingsboard.server.common.data.device.profile;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.thingsboard.server.common.data.id.DashboardId;
|
||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
@ -31,5 +32,6 @@ public class AlarmRule implements Serializable {
|
|||||||
// Advanced
|
// Advanced
|
||||||
@NoXss
|
@NoXss
|
||||||
private String alarmDetails;
|
private String alarmDetails;
|
||||||
|
private DashboardId dashboardId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
|
|||||||
import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType;
|
import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType;
|
||||||
import org.thingsboard.server.common.data.device.profile.AlarmConditionSpecType;
|
import org.thingsboard.server.common.data.device.profile.AlarmConditionSpecType;
|
||||||
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
|
import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
|
||||||
|
import org.thingsboard.server.common.data.id.DashboardId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
@ -269,16 +270,22 @@ class AlarmState {
|
|||||||
private JsonNode createDetails(AlarmRuleState ruleState) {
|
private JsonNode createDetails(AlarmRuleState ruleState) {
|
||||||
JsonNode alarmDetails;
|
JsonNode alarmDetails;
|
||||||
String alarmDetailsStr = ruleState.getAlarmRule().getAlarmDetails();
|
String alarmDetailsStr = ruleState.getAlarmRule().getAlarmDetails();
|
||||||
|
DashboardId dashboardId = ruleState.getAlarmRule().getDashboardId();
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(alarmDetailsStr)) {
|
if (StringUtils.isNotEmpty(alarmDetailsStr) || dashboardId != null) {
|
||||||
for (var keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) {
|
|
||||||
EntityKeyValue entityKeyValue = dataSnapshot.getValue(keyFilter.getKey());
|
|
||||||
if (entityKeyValue != null) {
|
|
||||||
alarmDetailsStr = alarmDetailsStr.replaceAll(String.format("\\$\\{%s}", keyFilter.getKey().getKey()), getValueAsString(entityKeyValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ObjectNode newDetails = JacksonUtil.newObjectNode();
|
ObjectNode newDetails = JacksonUtil.newObjectNode();
|
||||||
newDetails.put("data", alarmDetailsStr);
|
if (StringUtils.isNotEmpty(alarmDetailsStr)) {
|
||||||
|
for (var keyFilter : ruleState.getAlarmRule().getCondition().getCondition()) {
|
||||||
|
EntityKeyValue entityKeyValue = dataSnapshot.getValue(keyFilter.getKey());
|
||||||
|
if (entityKeyValue != null) {
|
||||||
|
alarmDetailsStr = alarmDetailsStr.replaceAll(String.format("\\$\\{%s}", keyFilter.getKey().getKey()), getValueAsString(entityKeyValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newDetails.put("data", alarmDetailsStr);
|
||||||
|
}
|
||||||
|
if (dashboardId != null) {
|
||||||
|
newDetails.put("dashboardId", dashboardId.getId().toString());
|
||||||
|
}
|
||||||
alarmDetails = newDetails;
|
alarmDetails = newDetails;
|
||||||
} else if (currentAlarm != null) {
|
} else if (currentAlarm != null) {
|
||||||
alarmDetails = currentAlarm.getDetails();
|
alarmDetails = currentAlarm.getDetails();
|
||||||
|
|||||||
@ -46,8 +46,9 @@
|
|||||||
formControlName="defaultRuleChainId">
|
formControlName="defaultRuleChainId">
|
||||||
</tb-rule-chain-autocomplete>
|
</tb-rule-chain-autocomplete>
|
||||||
<tb-dashboard-autocomplete
|
<tb-dashboard-autocomplete
|
||||||
placeholder="{{'device-profile.default-dashboard' | translate}}"
|
placeholder="{{'device-profile.mobile-dashboard' | translate}}"
|
||||||
formControlName="defaultDashboardId">
|
formControlName="defaultDashboardId">
|
||||||
|
<div tb-hint>{{'device-profile.mobile-dashboard-hint' | translate}}</div>
|
||||||
</tb-dashboard-autocomplete>
|
</tb-dashboard-autocomplete>
|
||||||
<tb-queue-type-list
|
<tb-queue-type-list
|
||||||
[queueType]="serviceType"
|
[queueType]="serviceType"
|
||||||
|
|||||||
@ -35,4 +35,16 @@
|
|||||||
<mat-icon>{{ disabled ? 'visibility' : (alarmRuleFormGroup.get('alarmDetails').value ? 'edit' : 'add') }}</mat-icon>
|
<mat-icon>{{ disabled ? 'visibility' : (alarmRuleFormGroup.get('alarmDetails').value ? 'edit' : 'add') }}</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="!disabled || alarmRuleFormGroup.get('dashboardId').value" fxLayout="column" fxLayoutAlign="start start"
|
||||||
|
fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">
|
||||||
|
<span class="tb-alarm-rule-dashboard title">
|
||||||
|
{{ ('device-profile.alarm-rule-mobile-dashboard' | translate) + ': ' }}
|
||||||
|
</span>
|
||||||
|
<tb-dashboard-autocomplete class="tb-alarm-rule-dashboard dashboard"
|
||||||
|
floatLabel="never"
|
||||||
|
placeholder="{{ 'device-profile.alarm-rule-no-mobile-dashboard' | translate }}"
|
||||||
|
formControlName="dashboardId">
|
||||||
|
<div tb-hint>{{'device-profile.alarm-rule-mobile-dashboard-hint' | translate}}</div>
|
||||||
|
</tb-dashboard-autocomplete>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,16 +18,24 @@
|
|||||||
.row {
|
.row {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
.tb-alarm-rule-details {
|
.tb-alarm-rule-details, .tb-alarm-rule-dashboard {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
cursor: pointer;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&.title {
|
&.title {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tb-alarm-rule-details {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.tb-alarm-rule-dashboard {
|
||||||
|
&.dashboard {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import {
|
|||||||
EditAlarmDetailsDialogData
|
EditAlarmDetailsDialogData
|
||||||
} from '@home/components/profile/alarm/edit-alarm-details-dialog.component';
|
} from '@home/components/profile/alarm/edit-alarm-details-dialog.component';
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
|
import { DashboardId } from '@shared/models/id/dashboard-id';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-alarm-rule',
|
selector: 'tb-alarm-rule',
|
||||||
@ -92,7 +93,8 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
|
|||||||
this.alarmRuleFormGroup = this.fb.group({
|
this.alarmRuleFormGroup = this.fb.group({
|
||||||
condition: [null, [Validators.required]],
|
condition: [null, [Validators.required]],
|
||||||
schedule: [null],
|
schedule: [null],
|
||||||
alarmDetails: [null]
|
alarmDetails: [null],
|
||||||
|
dashboardId: [null]
|
||||||
});
|
});
|
||||||
this.alarmRuleFormGroup.valueChanges.subscribe(() => {
|
this.alarmRuleFormGroup.valueChanges.subscribe(() => {
|
||||||
this.updateModel();
|
this.updateModel();
|
||||||
@ -110,7 +112,11 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
|
|||||||
|
|
||||||
writeValue(value: AlarmRule): void {
|
writeValue(value: AlarmRule): void {
|
||||||
this.modelValue = value;
|
this.modelValue = value;
|
||||||
this.alarmRuleFormGroup.reset(this.modelValue || undefined, {emitEvent: false});
|
const model = this.modelValue ? {
|
||||||
|
...this.modelValue,
|
||||||
|
dashboardId: this.modelValue.dashboardId?.id
|
||||||
|
} : null;
|
||||||
|
this.alarmRuleFormGroup.reset(model || undefined, {emitEvent: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
public openEditDetailsDialog($event: Event) {
|
public openEditDetailsDialog($event: Event) {
|
||||||
@ -143,7 +149,7 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
|
|||||||
private updateModel() {
|
private updateModel() {
|
||||||
const value = this.alarmRuleFormGroup.value;
|
const value = this.alarmRuleFormGroup.value;
|
||||||
if (this.modelValue) {
|
if (this.modelValue) {
|
||||||
this.modelValue = {...this.modelValue, ...value};
|
this.modelValue = {...this.modelValue, ...value, dashboardId: value.dashboardId ? new DashboardId(value.dashboardId) : null};
|
||||||
this.propagateChange(this.modelValue);
|
this.propagateChange(this.modelValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,8 +60,9 @@
|
|||||||
formControlName="defaultRuleChainId">
|
formControlName="defaultRuleChainId">
|
||||||
</tb-rule-chain-autocomplete>
|
</tb-rule-chain-autocomplete>
|
||||||
<tb-dashboard-autocomplete
|
<tb-dashboard-autocomplete
|
||||||
placeholder="{{'device-profile.default-dashboard' | translate}}"
|
placeholder="{{'device-profile.mobile-dashboard' | translate}}"
|
||||||
formControlName="defaultDashboardId">
|
formControlName="defaultDashboardId">
|
||||||
|
<div tb-hint>{{'device-profile.mobile-dashboard-hint' | translate}}</div>
|
||||||
</tb-dashboard-autocomplete>
|
</tb-dashboard-autocomplete>
|
||||||
<tb-queue-type-list
|
<tb-queue-type-list
|
||||||
[queueType]="serviceType"
|
[queueType]="serviceType"
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<mat-form-field [formGroup]="selectDashboardFormGroup" class="mat-block">
|
<mat-form-field [formGroup]="selectDashboardFormGroup" class="mat-block" [floatLabel]="floatLabel">
|
||||||
<input matInput type="text" placeholder="{{ placeholder || ('dashboard.dashboard' | translate) }}"
|
<input matInput type="text" placeholder="{{ placeholder || ('dashboard.dashboard' | translate) }}"
|
||||||
#dashboardInput
|
#dashboardInput
|
||||||
formControlName="dashboard"
|
formControlName="dashboard"
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import { getCurrentAuthUser } from '@app/core/auth/auth.selectors';
|
|||||||
import { Authority } from '@shared/models/authority.enum';
|
import { Authority } from '@shared/models/authority.enum';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
|
import { FloatLabelType } from '@angular/material/form-field/form-field';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-dashboard-autocomplete',
|
selector: 'tb-dashboard-autocomplete',
|
||||||
@ -64,6 +65,9 @@ export class DashboardAutocompleteComponent implements ControlValueAccessor, OnI
|
|||||||
@Input()
|
@Input()
|
||||||
customerId: string;
|
customerId: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
floatLabel: FloatLabelType = 'auto';
|
||||||
|
|
||||||
private requiredValue: boolean;
|
private requiredValue: boolean;
|
||||||
get required(): boolean {
|
get required(): boolean {
|
||||||
return this.requiredValue;
|
return this.requiredValue;
|
||||||
|
|||||||
@ -428,6 +428,7 @@ export interface CustomTimeSchedulerItem{
|
|||||||
export interface AlarmRule {
|
export interface AlarmRule {
|
||||||
condition: AlarmCondition;
|
condition: AlarmCondition;
|
||||||
alarmDetails?: string;
|
alarmDetails?: string;
|
||||||
|
dashboardId?: DashboardId;
|
||||||
schedule?: AlarmSchedule;
|
schedule?: AlarmSchedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1070,7 +1070,8 @@
|
|||||||
"profile-configuration": "Profile configuration",
|
"profile-configuration": "Profile configuration",
|
||||||
"transport-configuration": "Transport configuration",
|
"transport-configuration": "Transport configuration",
|
||||||
"default-rule-chain": "Default rule chain",
|
"default-rule-chain": "Default rule chain",
|
||||||
"default-dashboard": "Default dashboard",
|
"mobile-dashboard": "Mobile dashboard",
|
||||||
|
"mobile-dashboard-hint": "Used by mobile application as a device details dashboard",
|
||||||
"select-queue-hint": "Select from a drop-down list or add a custom name.",
|
"select-queue-hint": "Select from a drop-down list or add a custom name.",
|
||||||
"delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?",
|
"delete-device-profile-title": "Are you sure you want to delete the device profile '{{deviceProfileName}}'?",
|
||||||
"delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data will become unrecoverable.",
|
"delete-device-profile-text": "Be careful, after the confirmation the device profile and all related data will become unrecoverable.",
|
||||||
@ -1149,6 +1150,9 @@
|
|||||||
"advanced-settings": "Advanced settings",
|
"advanced-settings": "Advanced settings",
|
||||||
"alarm-rule-details": "Details",
|
"alarm-rule-details": "Details",
|
||||||
"add-alarm-rule-details": "Add details",
|
"add-alarm-rule-details": "Add details",
|
||||||
|
"alarm-rule-mobile-dashboard": "Mobile dashboard",
|
||||||
|
"alarm-rule-mobile-dashboard-hint": "Used by mobile application as an alarm details dashboard",
|
||||||
|
"alarm-rule-no-mobile-dashboard": "No dashboard selected",
|
||||||
"propagate-alarm": "Propagate alarm",
|
"propagate-alarm": "Propagate alarm",
|
||||||
"alarm-rule-relation-types-list": "Relation types to propagate",
|
"alarm-rule-relation-types-list": "Relation types to propagate",
|
||||||
"alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.",
|
"alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user