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 { 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,

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>
</div>
<div class="tb-condition-duration" fxFlex fxLayout="row" fxLayoutGap="8px">
<span style="min-width: 250px;" [fxShow]="!enableDuration"></span>
<div style="min-width: 250px;" fxLayout="row" fxLayoutGap="8px" [fxShow]="enableDuration">
<span style="min-width: 250px;" *ngIf="!enableDuration"></span>
<div style="min-width: 250px;" fxLayout="row" fxLayoutGap="8px" *ngIf="enableDuration">
<mat-form-field class="mat-block duration-value-field" hideRequiredMarker floatLabel="always">
<mat-label></mat-label>
<input type="number"
[required]="enableDuration"
required
step="1"
min="1" max="2147483647" matInput
placeholder="{{ 'device-profile.condition-duration-value' | translate }}"
@ -55,7 +55,7 @@
<mat-form-field class="mat-block duration-unit-field" hideRequiredMarker floatLabel="always">
<mat-label></mat-label>
<mat-select formControlName="durationUnit"
[required]="enableDuration"
required
placeholder="{{ 'device-profile.condition-duration-time-unit' | translate }}">
<mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">
{{ 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>
</button>
</div>
<div *ngIf="disabled && !createAlarmRulesFormArray().controls.length">
<div *ngIf="!createAlarmRulesFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-create-alarm-rules</span>
</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.updateUsedSeverities();
if (!this.disabled && !this.createAlarmRulesFormGroup.valid) {
this.updateModel();
}
}
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>
</button>
</div>
<div *ngIf="disabled && !alarmFormGroup.get('clearRule').value">
<div *ngIf="!alarmFormGroup.get('clearRule').value">
<span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-clear-alarm-rule</span>
</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;
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;
}
}
}

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

@ -25,6 +25,10 @@
</tb-device-profile-alarm>
</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"
style="padding-top: 16px;">
<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() {
// if (this.deviceProfileAlarmsFormGroup.valid) {
const alarms: Array<DeviceProfileAlarm> = this.deviceProfileAlarmsFormGroup.get('alarms').value;
this.propagateChange(alarms);
/* } else {
this.propagateChange(null);
} */
const alarms: Array<DeviceProfileAlarm> = this.deviceProfileAlarmsFormGroup.get('alarms').value;
this.propagateChange(alarms);
}
}

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

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

@ -81,7 +81,7 @@
required>
</tb-device-profile-data>
<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>
</mat-form-field>
</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 { DeviceProfileComponent } from '../../components/profile/device-profile.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()
export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableConfig<DeviceProfile>> {
@ -44,7 +50,8 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
constructor(private deviceProfileService: DeviceProfileService,
private translate: TranslateService,
private datePipe: DatePipe,
private dialogService: DialogService) {
private dialogService: DialogService,
private dialog: MatDialog) {
this.config.entityType = EntityType.DEVICE_PROFILE;
this.config.entityComponent = DeviceProfileComponent;
@ -92,6 +99,7 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
this.config.onEntityAction = action => this.onDeviceProfileAction(action);
this.config.deleteEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default;
this.config.entitySelectionEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default;
this.config.addEntity = () => this.addDeviceProfile();
}
resolve(): EntityTableConfig<DeviceProfile> {
@ -100,6 +108,17 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
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) {
if ($event) {
$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>.",
"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}})",
"no-alarm-rules": "No alarm rules configured",
"add-alarm-rule": "Add alarm rule",
"edit-alarm-rule": "Edit alarm rule",
"alarm-type": "Alarm type",

Loading…
Cancel
Save