diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts
index d9771d844e..0f8b4a88cf 100644
--- a/ui-ngx/src/app/modules/home/components/home-components.module.ts
+++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts
@@ -105,6 +105,7 @@ import { AlarmRuleComponent } from './profile/alarm/alarm-rule.component';
import { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-condition.component';
import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-key-filters-dialog.component';
import { FilterTextComponent } from './filter/filter-text.component';
+import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component';
@NgModule({
declarations:
@@ -192,7 +193,8 @@ import { FilterTextComponent } from './filter/filter-text.component';
DeviceProfileAlarmsComponent,
DeviceProfileDataComponent,
DeviceProfileComponent,
- DeviceProfileDialogComponent
+ DeviceProfileDialogComponent,
+ AddDeviceProfileDialogComponent
],
imports: [
CommonModule,
@@ -269,7 +271,8 @@ import { FilterTextComponent } from './filter/filter-text.component';
DeviceProfileAlarmsComponent,
DeviceProfileDataComponent,
DeviceProfileComponent,
- DeviceProfileDialogComponent
+ DeviceProfileDialogComponent,
+ AddDeviceProfileDialogComponent
],
providers: [
WidgetComponentService,
diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html
new file mode 100644
index 0000000000..5e1c4adfd6
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html
@@ -0,0 +1,114 @@
+
+
+
+ device-profile.add
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss
new file mode 100644
index 0000000000..cafcce74b6
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss
@@ -0,0 +1,38 @@
+/**
+ * Copyright © 2016-2020 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 {
+ .mat-dialog-content {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+
+ .mat-stepper-horizontal {
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+ }
+}
+
+:host ::ng-deep {
+ .mat-dialog-content {
+ .mat-stepper-horizontal {
+ .mat-horizontal-content-container {
+ overflow: auto;
+ }
+ }
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
new file mode 100644
index 0000000000..476c69488f
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
@@ -0,0 +1,173 @@
+///
+/// Copyright © 2016-2020 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 {
+ AfterViewInit,
+ Component,
+ ComponentFactoryResolver,
+ Inject,
+ Injector,
+ SkipSelf,
+ ViewChild
+} from '@angular/core';
+import { ErrorStateMatcher } from '@angular/material/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { Store } from '@ngrx/store';
+import { AppState } from '@core/core.state';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { DialogComponent } from '@shared/components/dialog.component';
+import { Router } from '@angular/router';
+import {
+ createDeviceProfileConfiguration,
+ createDeviceProfileTransportConfiguration,
+ DeviceProfile,
+ DeviceProfileType,
+ deviceProfileTypeTranslationMap,
+ DeviceTransportType,
+ deviceTransportTypeTranslationMap
+} from '@shared/models/device.models';
+import { DeviceProfileService } from '@core/http/device-profile.service';
+import { EntityType } from '@shared/models/entity-type.models';
+import { MatHorizontalStepper } from '@angular/material/stepper';
+import { RuleChainId } from '@shared/models/id/rule-chain-id';
+
+export interface AddDeviceProfileDialogData {
+ deviceProfileName: string;
+}
+
+@Component({
+ selector: 'tb-add-device-profile-dialog',
+ templateUrl: './add-device-profile-dialog.component.html',
+ providers: [],
+ styleUrls: ['./add-device-profile-dialog.component.scss']
+})
+export class AddDeviceProfileDialogComponent extends
+ DialogComponent implements AfterViewInit {
+
+ @ViewChild('addDeviceProfileStepper', {static: true}) addDeviceProfileStepper: MatHorizontalStepper;
+
+ selectedIndex = 0;
+
+ entityType = EntityType;
+
+ deviceProfileTypes = Object.keys(DeviceProfileType);
+
+ deviceProfileTypeTranslations = deviceProfileTypeTranslationMap;
+
+ deviceTransportTypes = Object.keys(DeviceTransportType);
+
+ deviceTransportTypeTranslations = deviceTransportTypeTranslationMap;
+
+ deviceProfileDetailsFormGroup: FormGroup;
+
+ transportConfigFormGroup: FormGroup;
+
+ alarmRulesFormGroup: FormGroup;
+
+ constructor(protected store: Store,
+ protected router: Router,
+ @Inject(MAT_DIALOG_DATA) public data: AddDeviceProfileDialogData,
+ public dialogRef: MatDialogRef,
+ private componentFactoryResolver: ComponentFactoryResolver,
+ private injector: Injector,
+ @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
+ private deviceProfileService: DeviceProfileService,
+ private fb: FormBuilder) {
+ super(store, router, dialogRef);
+ this.deviceProfileDetailsFormGroup = this.fb.group(
+ {
+ name: [data.deviceProfileName, [Validators.required]],
+ type: [DeviceProfileType.DEFAULT, [Validators.required]],
+ defaultRuleChainId: [null, []],
+ description: ['', []]
+ }
+ );
+ this.transportConfigFormGroup = this.fb.group(
+ {
+ transportType: [DeviceTransportType.DEFAULT, [Validators.required]],
+ transportConfiguration: [createDeviceProfileTransportConfiguration(DeviceTransportType.DEFAULT),
+ [Validators.required]]
+ }
+ );
+ this.transportConfigFormGroup.get('transportType').valueChanges.subscribe(() => {
+ this.deviceProfileTransportTypeChanged();
+ });
+
+ this.alarmRulesFormGroup = this.fb.group(
+ {
+ alarms: [null]
+ }
+ );
+ }
+
+ private deviceProfileTransportTypeChanged() {
+ const deviceTransportType: DeviceTransportType = this.transportConfigFormGroup.get('transportType').value;
+ this.transportConfigFormGroup.patchValue(
+ {transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)});
+ }
+
+ ngAfterViewInit(): void {
+ }
+
+ cancel(): void {
+ this.dialogRef.close(null);
+ }
+
+ previousStep() {
+ this.addDeviceProfileStepper.previous();
+ }
+
+ nextStep() {
+ if (this.selectedIndex < 2) {
+ this.addDeviceProfileStepper.next();
+ } else {
+ this.add();
+ }
+ }
+
+ selectedForm(): FormGroup {
+ switch (this.selectedIndex) {
+ case 0:
+ return this.deviceProfileDetailsFormGroup;
+ case 1:
+ return this.transportConfigFormGroup;
+ case 2:
+ return this.alarmRulesFormGroup;
+ }
+ }
+
+ private add(): void {
+ const deviceProfile: DeviceProfile = {
+ name: this.deviceProfileDetailsFormGroup.get('name').value,
+ type: this.deviceProfileDetailsFormGroup.get('type').value,
+ transportType: this.transportConfigFormGroup.get('transportType').value,
+ description: this.deviceProfileDetailsFormGroup.get('description').value,
+ profileData: {
+ configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT),
+ transportConfiguration: this.transportConfigFormGroup.get('transportConfiguration').value,
+ alarms: this.alarmRulesFormGroup.get('alarms').value
+ }
+ };
+ if (this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value) {
+ deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceProfileDetailsFormGroup.get('defaultRuleChainId').value);
+ }
+ this.deviceProfileService.saveDeviceProfile(deviceProfile).subscribe(
+ (savedDeviceProfile) => {
+ this.dialogRef.close(savedDeviceProfile);
+ }
+ );
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html
index 2ba8ab183f..ef69037727 100644
--- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html
+++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html
@@ -32,12 +32,12 @@
-
-
+
+
{{ timeUnitTranslations.get(timeUnit) | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html
index c3ac14c757..121df96386 100644
--- a/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html
+++ b/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html
@@ -46,7 +46,7 @@
remove_circle_outline
-
+
device-profile.no-create-alarm-rules
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts
index caebff80b4..6dac1f341e 100644
--- a/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts
+++ b/ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts
@@ -124,6 +124,9 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
this.updateModel();
});
this.updateUsedSeverities();
+ if (!this.disabled && !this.createAlarmRulesFormGroup.valid) {
+ this.updateModel();
+ }
}
public removeCreateAlarmRule(index: number) {
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html
index d827245abf..d4a72da751 100644
--- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html
+++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html
@@ -67,7 +67,7 @@
remove_circle_outline
-
+
device-profile.no-clear-alarm-rule
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts
index 8befb6204d..7fa60e79d5 100644
--- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts
+++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts
@@ -63,7 +63,8 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
alarmFormGroup: FormGroup;
- private propagateChange = (v: any) => { };
+ private propagateChange = null;
+ private propagateChangePending = false;
constructor(private dialog: MatDialog,
private fb: FormBuilder) {
@@ -71,6 +72,12 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
registerOnChange(fn: any): void {
this.propagateChange = fn;
+ if (this.propagateChangePending) {
+ this.propagateChangePending = false;
+ setTimeout(() => {
+ this.propagateChange(this.modelValue);
+ }, 0);
+ }
}
registerOnTouched(fn: any): void {
@@ -100,11 +107,15 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
}
writeValue(value: DeviceProfileAlarm): void {
+ this.propagateChangePending = false;
this.modelValue = value;
if (!this.modelValue.alarmType) {
this.expanded = true;
}
this.alarmFormGroup.reset(this.modelValue || undefined, {emitEvent: false});
+ if (!this.disabled && !this.alarmFormGroup.valid) {
+ this.updateModel();
+ }
}
public addClearAlarmRule() {
@@ -160,6 +171,10 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
private updateModel() {
const value = this.alarmFormGroup.value;
this.modelValue = {...this.modelValue, ...value};
- this.propagateChange(this.modelValue);
+ if (this.propagateChange) {
+ this.propagateChange(this.modelValue);
+ } else {
+ this.propagateChangePending = true;
+ }
}
}
diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html
index d07e8b0fed..7bd7c546db 100644
--- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html
+++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html
@@ -25,6 +25,10 @@
+
+ device-profile.no-alarm-rules
+