Browse Source

UI: Add device profile wizard

pull/3477/head
Igor Kulikov 6 years ago
parent
commit
3dc7fde4db
  1. 7
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  2. 114
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html
  3. 38
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.scss
  4. 173
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
  5. 8
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html
  6. 2
      ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html
  7. 3
      ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts
  8. 2
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html
  9. 19
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts
  10. 4
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html
  11. 8
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.ts
  12. 43
      ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.ts
  13. 2
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.html
  14. 21
      ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts
  15. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

7
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 { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-condition.component';
import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-key-filters-dialog.component'; import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-key-filters-dialog.component';
import { FilterTextComponent } from './filter/filter-text.component'; import { FilterTextComponent } from './filter/filter-text.component';
import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -192,7 +193,8 @@ import { FilterTextComponent } from './filter/filter-text.component';
DeviceProfileAlarmsComponent, DeviceProfileAlarmsComponent,
DeviceProfileDataComponent, DeviceProfileDataComponent,
DeviceProfileComponent, DeviceProfileComponent,
DeviceProfileDialogComponent DeviceProfileDialogComponent,
AddDeviceProfileDialogComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -269,7 +271,8 @@ import { FilterTextComponent } from './filter/filter-text.component';
DeviceProfileAlarmsComponent, DeviceProfileAlarmsComponent,
DeviceProfileDataComponent, DeviceProfileDataComponent,
DeviceProfileComponent, DeviceProfileComponent,
DeviceProfileDialogComponent DeviceProfileDialogComponent,
AddDeviceProfileDialogComponent
], ],
providers: [ providers: [
WidgetComponentService, WidgetComponentService,

114
ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html

@ -0,0 +1,114 @@
<!--
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.
-->
<div style="min-width: 1000px;">
<mat-toolbar color="primary">
<h2 translate>device-profile.add</h2>
<span fxFlex></span>
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div mat-dialog-content>
<mat-horizontal-stepper [linear]="true" #addDeviceProfileStepper (selectionChange)="selectedIndex = $event.selectedIndex">
<mat-step [stepControl]="deviceProfileDetailsFormGroup">
<form [formGroup]="deviceProfileDetailsFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{ 'device-profile.device-profile-details' | translate }}</ng-template>
<fieldset [disabled]="isLoading$ | async">
<mat-form-field class="mat-block">
<mat-label translate>device-profile.name</mat-label>
<input matInput formControlName="name" required/>
<mat-error *ngIf="deviceProfileDetailsFormGroup.get('name').hasError('required')">
{{ 'device-profile.name-required' | translate }}
</mat-error>
</mat-form-field>
<tb-entity-autocomplete
labelText="device-profile.default-rule-chain"
[entityType]="entityType.RULE_CHAIN"
formControlName="defaultRuleChainId">
</tb-entity-autocomplete>
<mat-form-field class="mat-block">
<mat-label translate>device-profile.type</mat-label>
<mat-select formControlName="type" required>
<mat-option *ngFor="let type of deviceProfileTypes" [value]="type">
{{deviceProfileTypeTranslations.get(type) | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="deviceProfileDetailsFormGroup.get('type').hasError('required')">
{{ 'device-profile.type-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>device-profile.description</mat-label>
<textarea matInput formControlName="description" rows="2"></textarea>
</mat-form-field>
</fieldset>
</form>
</mat-step>
<mat-step [stepControl]="transportConfigFormGroup">
<form [formGroup]="transportConfigFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{ 'device-profile.transport-configuration' | translate }}</ng-template>
<mat-form-field class="mat-block">
<mat-label translate>device-profile.transport-type</mat-label>
<mat-select formControlName="transportType" required>
<mat-option *ngFor="let type of deviceTransportTypes" [value]="type">
{{deviceTransportTypeTranslations.get(type) | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="transportConfigFormGroup.get('transportType').hasError('required')">
{{ 'device-profile.transport-type-required' | translate }}
</mat-error>
</mat-form-field>
<tb-device-profile-transport-configuration
formControlName="transportConfiguration"
required>
</tb-device-profile-transport-configuration>
</form>
</mat-step>
<mat-step [stepControl]="alarmRulesFormGroup">
<form [formGroup]="alarmRulesFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{'device-profile.alarm-rules' | translate:
{count: alarmRulesFormGroup.get('alarms').value ?
alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template>
<tb-device-profile-alarms
formControlName="alarms">
</tb-device-profile-alarms>
</form>
</mat-step>
</mat-horizontal-stepper>
</div>
<div mat-dialog-actions fxLayout="row wrap" fxLayoutAlign="space-between center">
<button mat-button *ngIf="selectedIndex > 0"
[disabled]="(isLoading$ | async)"
(click)="previousStep()">{{ 'action.back' | translate }}</button>
<span *ngIf="selectedIndex <= 0"></span>
<div fxLayout="row wrap" fxLayoutGap="20px">
<button mat-button
[disabled]="(isLoading$ | async)"
(click)="cancel()">{{ 'action.cancel' | translate }}</button>
<button mat-raised-button
[disabled]="(isLoading$ | async) || selectedForm().invalid"
color="primary"
(click)="nextStep()">{{ (selectedIndex === 2 ? 'action.add' : 'action.continue') | translate }}</button>
</div>
</div>
</div>

38
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;
}
}
}
}

173
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<AddDeviceProfileDialogComponent, DeviceProfile> 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<AppState>,
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: AddDeviceProfileDialogData,
public dialogRef: MatDialogRef<AddDeviceProfileDialogComponent, DeviceProfile>,
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);
}
);
}
}

8
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html

@ -32,12 +32,12 @@
</mat-slide-toggle> </mat-slide-toggle>
</div> </div>
<div class="tb-condition-duration" fxFlex fxLayout="row" fxLayoutGap="8px"> <div class="tb-condition-duration" fxFlex fxLayout="row" fxLayoutGap="8px">
<span style="min-width: 250px;" [fxShow]="!enableDuration"></span> <span style="min-width: 250px;" *ngIf="!enableDuration"></span>
<div style="min-width: 250px;" fxLayout="row" fxLayoutGap="8px" [fxShow]="enableDuration"> <div style="min-width: 250px;" fxLayout="row" fxLayoutGap="8px" *ngIf="enableDuration">
<mat-form-field class="mat-block duration-value-field" hideRequiredMarker floatLabel="always"> <mat-form-field class="mat-block duration-value-field" hideRequiredMarker floatLabel="always">
<mat-label></mat-label> <mat-label></mat-label>
<input type="number" <input type="number"
[required]="enableDuration" required
step="1" step="1"
min="1" max="2147483647" matInput min="1" max="2147483647" matInput
placeholder="{{ 'device-profile.condition-duration-value' | translate }}" placeholder="{{ 'device-profile.condition-duration-value' | translate }}"
@ -55,7 +55,7 @@
<mat-form-field class="mat-block duration-unit-field" hideRequiredMarker floatLabel="always"> <mat-form-field class="mat-block duration-unit-field" hideRequiredMarker floatLabel="always">
<mat-label></mat-label> <mat-label></mat-label>
<mat-select formControlName="durationUnit" <mat-select formControlName="durationUnit"
[required]="enableDuration" required
placeholder="{{ 'device-profile.condition-duration-time-unit' | translate }}"> placeholder="{{ 'device-profile.condition-duration-time-unit' | translate }}">
<mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit"> <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">
{{ timeUnitTranslations.get(timeUnit) | translate }} {{ timeUnitTranslations.get(timeUnit) | translate }}

2
ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html

@ -46,7 +46,7 @@
<mat-icon>remove_circle_outline</mat-icon> <mat-icon>remove_circle_outline</mat-icon>
</button> </button>
</div> </div>
<div *ngIf="disabled && !createAlarmRulesFormArray().controls.length"> <div *ngIf="!createAlarmRulesFormArray().controls.length">
<span translate fxLayoutAlign="center center" <span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-create-alarm-rules</span> class="tb-prompt">device-profile.no-create-alarm-rules</span>
</div> </div>

3
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.updateModel();
}); });
this.updateUsedSeverities(); this.updateUsedSeverities();
if (!this.disabled && !this.createAlarmRulesFormGroup.valid) {
this.updateModel();
}
} }
public removeCreateAlarmRule(index: number) { public removeCreateAlarmRule(index: number) {

2
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html

@ -67,7 +67,7 @@
<mat-icon>remove_circle_outline</mat-icon> <mat-icon>remove_circle_outline</mat-icon>
</button> </button>
</div> </div>
<div *ngIf="disabled && !alarmFormGroup.get('clearRule').value"> <div *ngIf="!alarmFormGroup.get('clearRule').value">
<span translate fxLayoutAlign="center center" <span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-clear-alarm-rule</span> class="tb-prompt">device-profile.no-clear-alarm-rule</span>
</div> </div>

19
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; alarmFormGroup: FormGroup;
private propagateChange = (v: any) => { }; private propagateChange = null;
private propagateChangePending = false;
constructor(private dialog: MatDialog, constructor(private dialog: MatDialog,
private fb: FormBuilder) { private fb: FormBuilder) {
@ -71,6 +72,12 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
this.propagateChange = fn; this.propagateChange = fn;
if (this.propagateChangePending) {
this.propagateChangePending = false;
setTimeout(() => {
this.propagateChange(this.modelValue);
}, 0);
}
} }
registerOnTouched(fn: any): void { registerOnTouched(fn: any): void {
@ -100,11 +107,15 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
} }
writeValue(value: DeviceProfileAlarm): void { writeValue(value: DeviceProfileAlarm): void {
this.propagateChangePending = false;
this.modelValue = value; this.modelValue = value;
if (!this.modelValue.alarmType) { if (!this.modelValue.alarmType) {
this.expanded = true; this.expanded = true;
} }
this.alarmFormGroup.reset(this.modelValue || undefined, {emitEvent: false}); this.alarmFormGroup.reset(this.modelValue || undefined, {emitEvent: false});
if (!this.disabled && !this.alarmFormGroup.valid) {
this.updateModel();
}
} }
public addClearAlarmRule() { public addClearAlarmRule() {
@ -160,6 +171,10 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
private updateModel() { private updateModel() {
const value = this.alarmFormGroup.value; const value = this.alarmFormGroup.value;
this.modelValue = {...this.modelValue, ...value}; this.modelValue = {...this.modelValue, ...value};
this.propagateChange(this.modelValue); if (this.propagateChange) {
this.propagateChange(this.modelValue);
} else {
this.propagateChangePending = true;
}
} }
} }

4
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html

@ -25,6 +25,10 @@
</tb-device-profile-alarm> </tb-device-profile-alarm>
</div> </div>
</div> </div>
<div *ngIf="!alarmsFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-alarm-rules</span>
</div>
<div *ngIf="!disabled" fxFlex fxLayout="row" fxLayoutAlign="end center" <div *ngIf="!disabled" fxFlex fxLayout="row" fxLayoutAlign="end center"
style="padding-top: 16px;"> style="padding-top: 16px;">
<button mat-raised-button color="primary" <button mat-raised-button color="primary"

8
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.ts

@ -162,11 +162,7 @@ export class DeviceProfileAlarmsComponent implements ControlValueAccessor, OnIni
} }
private updateModel() { private updateModel() {
// if (this.deviceProfileAlarmsFormGroup.valid) { const alarms: Array<DeviceProfileAlarm> = this.deviceProfileAlarmsFormGroup.get('alarms').value;
const alarms: Array<DeviceProfileAlarm> = this.deviceProfileAlarmsFormGroup.get('alarms').value; this.propagateChange(alarms);
this.propagateChange(alarms);
/* } else {
this.propagateChange(null);
} */
} }
} }

43
ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.ts

@ -49,6 +49,7 @@ import {
import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfileService } from '@core/http/device-profile.service';
import { DeviceProfileDialogComponent, DeviceProfileDialogData } from './device-profile-dialog.component'; import { DeviceProfileDialogComponent, DeviceProfileDialogData } from './device-profile-dialog.component';
import { MatAutocomplete } from '@angular/material/autocomplete'; import { MatAutocomplete } from '@angular/material/autocomplete';
import { AddDeviceProfileDialogComponent, AddDeviceProfileDialogData } from './add-device-profile-dialog.component';
@Component({ @Component({
selector: 'tb-device-profile-autocomplete', selector: 'tb-device-profile-autocomplete',
@ -279,15 +280,8 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
createDeviceProfile($event: Event, profileName: string) { createDeviceProfile($event: Event, profileName: string) {
$event.preventDefault(); $event.preventDefault();
const deviceProfile: DeviceProfile = { const deviceProfile: DeviceProfile = {
id: null, name: profileName
name: profileName, } as DeviceProfile;
type: DeviceProfileType.DEFAULT,
transportType: DeviceTransportType.DEFAULT,
profileData: {
configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT),
transportConfiguration: createDeviceProfileTransportConfiguration(DeviceTransportType.DEFAULT)
}
};
this.openDeviceProfileDialog(deviceProfile, true); this.openDeviceProfileDialog(deviceProfile, true);
} }
@ -301,15 +295,28 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
} }
openDeviceProfileDialog(deviceProfile: DeviceProfile, isAdd: boolean) { openDeviceProfileDialog(deviceProfile: DeviceProfile, isAdd: boolean) {
this.dialog.open<DeviceProfileDialogComponent, DeviceProfileDialogData, let deviceProfileObservable: Observable<DeviceProfile>;
DeviceProfile>(DeviceProfileDialogComponent, { if (!isAdd) {
disableClose: true, deviceProfileObservable = this.dialog.open<DeviceProfileDialogComponent, DeviceProfileDialogData,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], DeviceProfile>(DeviceProfileDialogComponent, {
data: { disableClose: true,
isAdd, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
deviceProfile data: {
} isAdd: false,
}).afterClosed().subscribe( deviceProfile
}
}).afterClosed();
} else {
deviceProfileObservable = this.dialog.open<AddDeviceProfileDialogComponent, AddDeviceProfileDialogData,
DeviceProfile>(AddDeviceProfileDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
deviceProfileName: deviceProfile.name
}
}).afterClosed();
}
deviceProfileObservable.subscribe(
(savedDeviceProfile) => { (savedDeviceProfile) => {
if (!savedDeviceProfile) { if (!savedDeviceProfile) {
setTimeout(() => { setTimeout(() => {

2
ui-ngx/src/app/modules/home/components/profile/device-profile.component.html

@ -81,7 +81,7 @@
required> required>
</tb-device-profile-data> </tb-device-profile-data>
<mat-form-field class="mat-block"> <mat-form-field class="mat-block">
<mat-label translate>tenant-profile.description</mat-label> <mat-label translate>device-profile.description</mat-label>
<textarea matInput formControlName="description" rows="2"></textarea> <textarea matInput formControlName="description" rows="2"></textarea>
</mat-form-field> </mat-form-field>
</fieldset> </fieldset>

21
ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts

@ -35,6 +35,12 @@ import {
import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfileService } from '@core/http/device-profile.service';
import { DeviceProfileComponent } from '../../components/profile/device-profile.component'; import { DeviceProfileComponent } from '../../components/profile/device-profile.component';
import { DeviceProfileTabsComponent } from './device-profile-tabs.component'; import { DeviceProfileTabsComponent } from './device-profile-tabs.component';
import { Observable } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
import {
AddDeviceProfileDialogComponent,
AddDeviceProfileDialogData
} from '../../components/profile/add-device-profile-dialog.component';
@Injectable() @Injectable()
export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableConfig<DeviceProfile>> { export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableConfig<DeviceProfile>> {
@ -44,7 +50,8 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
constructor(private deviceProfileService: DeviceProfileService, constructor(private deviceProfileService: DeviceProfileService,
private translate: TranslateService, private translate: TranslateService,
private datePipe: DatePipe, private datePipe: DatePipe,
private dialogService: DialogService) { private dialogService: DialogService,
private dialog: MatDialog) {
this.config.entityType = EntityType.DEVICE_PROFILE; this.config.entityType = EntityType.DEVICE_PROFILE;
this.config.entityComponent = DeviceProfileComponent; this.config.entityComponent = DeviceProfileComponent;
@ -92,6 +99,7 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
this.config.onEntityAction = action => this.onDeviceProfileAction(action); this.config.onEntityAction = action => this.onDeviceProfileAction(action);
this.config.deleteEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default; this.config.deleteEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default;
this.config.entitySelectionEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default; this.config.entitySelectionEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default;
this.config.addEntity = () => this.addDeviceProfile();
} }
resolve(): EntityTableConfig<DeviceProfile> { resolve(): EntityTableConfig<DeviceProfile> {
@ -100,6 +108,17 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
return this.config; return this.config;
} }
addDeviceProfile(): Observable<DeviceProfile> {
return this.dialog.open<AddDeviceProfileDialogComponent, AddDeviceProfileDialogData,
DeviceProfile>(AddDeviceProfileDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
deviceProfileName: null
}
}).afterClosed();
}
setDefaultDeviceProfile($event: Event, deviceProfile: DeviceProfile) { setDefaultDeviceProfile($event: Event, deviceProfile: DeviceProfile) {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();

1
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -811,6 +811,7 @@
"single-level-wildcards-hint": "<code>[+]</code> is suitable for any topic filter level. Ex.: <b>v1/devices/+/telemetry</b> or <b>+/devices/+/attributes</b>.", "single-level-wildcards-hint": "<code>[+]</code> is suitable for any topic filter level. Ex.: <b>v1/devices/+/telemetry</b> or <b>+/devices/+/attributes</b>.",
"multi-level-wildcards-hint": "<code>[#]</code> can replace the topic filter itself and must be the last symbol of the topic. Ex.: <b>#</b> or <b>v1/devices/me/#</b>.", "multi-level-wildcards-hint": "<code>[#]</code> can replace the topic filter itself and must be the last symbol of the topic. Ex.: <b>#</b> or <b>v1/devices/me/#</b>.",
"alarm-rules": "Alarm rules ({{count}})", "alarm-rules": "Alarm rules ({{count}})",
"no-alarm-rules": "No alarm rules configured",
"add-alarm-rule": "Add alarm rule", "add-alarm-rule": "Add alarm rule",
"edit-alarm-rule": "Edit alarm rule", "edit-alarm-rule": "Edit alarm rule",
"alarm-type": "Alarm type", "alarm-type": "Alarm type",

Loading…
Cancel
Save