Add mobile dashboard to alarm rules

This commit is contained in:
Igor Kulikov 2021-06-14 15:42:27 +03:00
parent 5afc39eb60
commit b4566a93fd
11 changed files with 66 additions and 20 deletions

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.device.profile;
import lombok.Data;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.validation.NoXss;
import javax.validation.Valid;
@ -31,5 +32,6 @@ public class AlarmRule implements Serializable {
// Advanced
@NoXss
private String alarmDetails;
private DashboardId dashboardId;
}

View File

@ -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.AlarmConditionSpecType;
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.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -269,16 +270,22 @@ class AlarmState {
private JsonNode createDetails(AlarmRuleState ruleState) {
JsonNode alarmDetails;
String alarmDetailsStr = ruleState.getAlarmRule().getAlarmDetails();
DashboardId dashboardId = ruleState.getAlarmRule().getDashboardId();
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));
}
}
if (StringUtils.isNotEmpty(alarmDetailsStr) || dashboardId != null) {
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;
} else if (currentAlarm != null) {
alarmDetails = currentAlarm.getDetails();

View File

@ -46,8 +46,9 @@
formControlName="defaultRuleChainId">
</tb-rule-chain-autocomplete>
<tb-dashboard-autocomplete
placeholder="{{'device-profile.default-dashboard' | translate}}"
placeholder="{{'device-profile.mobile-dashboard' | translate}}"
formControlName="defaultDashboardId">
<div tb-hint>{{'device-profile.mobile-dashboard-hint' | translate}}</div>
</tb-dashboard-autocomplete>
<tb-queue-type-list
[queueType]="serviceType"

View File

@ -35,4 +35,16 @@
<mat-icon>{{ disabled ? 'visibility' : (alarmRuleFormGroup.get('alarmDetails').value ? 'edit' : 'add') }}</mat-icon>
</button>
</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>

View File

@ -18,16 +18,24 @@
.row {
margin-top: 1em;
}
.tb-alarm-rule-details {
.tb-alarm-rule-details, .tb-alarm-rule-dashboard {
padding: 4px;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&.title {
opacity: 0.7;
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;
}
}
}

View File

@ -34,6 +34,7 @@ import {
EditAlarmDetailsDialogData
} from '@home/components/profile/alarm/edit-alarm-details-dialog.component';
import { EntityId } from '@shared/models/id/entity-id';
import { DashboardId } from '@shared/models/id/dashboard-id';
@Component({
selector: 'tb-alarm-rule',
@ -92,7 +93,8 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
this.alarmRuleFormGroup = this.fb.group({
condition: [null, [Validators.required]],
schedule: [null],
alarmDetails: [null]
alarmDetails: [null],
dashboardId: [null]
});
this.alarmRuleFormGroup.valueChanges.subscribe(() => {
this.updateModel();
@ -110,7 +112,11 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
writeValue(value: AlarmRule): void {
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) {
@ -143,7 +149,7 @@ export class AlarmRuleComponent implements ControlValueAccessor, OnInit, Validat
private updateModel() {
const value = this.alarmRuleFormGroup.value;
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);
}
}

View File

@ -60,8 +60,9 @@
formControlName="defaultRuleChainId">
</tb-rule-chain-autocomplete>
<tb-dashboard-autocomplete
placeholder="{{'device-profile.default-dashboard' | translate}}"
placeholder="{{'device-profile.mobile-dashboard' | translate}}"
formControlName="defaultDashboardId">
<div tb-hint>{{'device-profile.mobile-dashboard-hint' | translate}}</div>
</tb-dashboard-autocomplete>
<tb-queue-type-list
[queueType]="serviceType"

View File

@ -15,7 +15,7 @@
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) }}"
#dashboardInput
formControlName="dashboard"

View File

@ -29,6 +29,7 @@ import { getCurrentAuthUser } from '@app/core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { FloatLabelType } from '@angular/material/form-field/form-field';
@Component({
selector: 'tb-dashboard-autocomplete',
@ -64,6 +65,9 @@ export class DashboardAutocompleteComponent implements ControlValueAccessor, OnI
@Input()
customerId: string;
@Input()
floatLabel: FloatLabelType = 'auto';
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;

View File

@ -428,6 +428,7 @@ export interface CustomTimeSchedulerItem{
export interface AlarmRule {
condition: AlarmCondition;
alarmDetails?: string;
dashboardId?: DashboardId;
schedule?: AlarmSchedule;
}

View File

@ -1070,7 +1070,8 @@
"profile-configuration": "Profile configuration",
"transport-configuration": "Transport configuration",
"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.",
"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.",
@ -1149,6 +1150,9 @@
"advanced-settings": "Advanced settings",
"alarm-rule-details": "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",
"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.",