Add Device Wizard improvements

This commit is contained in:
Igor Kulikov 2020-10-09 17:19:51 +03:00
parent e10696087e
commit c7b57ca543
9 changed files with 253 additions and 149 deletions

View File

@ -85,7 +85,7 @@
</mat-step>
<mat-step [stepControl]="alarmRulesFormGroup">
<form [formGroup]="alarmRulesFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{'device-profile.alarm-rules' | translate:
<ng-template matStepLabel>{{'device-profile.alarm-rules-with-count' | translate:
{count: alarmRulesFormGroup.get('alarms').value ?
alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template>
<tb-device-profile-alarms

View File

@ -20,9 +20,9 @@ import {
EventEmitter,
forwardRef,
Input,
NgZone,
NgZone, OnChanges,
OnInit,
Output,
Output, SimpleChanges,
ViewChild
} from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
@ -55,7 +55,7 @@ import { AddDeviceProfileDialogComponent, AddDeviceProfileDialogData } from './a
multi: true
}]
})
export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, OnInit {
export class DeviceProfileAutocompleteComponent implements ControlValueAccessor, OnInit, OnChanges {
selectDeviceProfileFormGroup: FormGroup;
@ -168,11 +168,22 @@ export class DeviceProfileAutocompleteComponent implements ControlValueAccessor,
);
}
ngOnChanges(changes: SimpleChanges): void {
for (const propName of Object.keys(changes)) {
const change = changes[propName];
if (!change.firstChange && change.currentValue !== change.previousValue) {
if (propName === 'transportType') {
this.writeValue(null);
}
}
}
}
selectDefaultDeviceProfileIfNeeded(): void {
if (this.selectDefaultProfile && !this.modelValue) {
this.deviceProfileService.getDefaultDeviceProfileInfo().subscribe(
(profile) => {
if (profile) {
if (profile && !this.transportType || (profile.transportType === this.transportType)) {
this.selectDeviceProfileFormGroup.get('deviceProfile').patchValue(profile, {emitEvent: false});
this.updateView(profile);
}

View File

@ -42,7 +42,7 @@
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
<div>{{'device-profile.alarm-rules' | translate:
<div>{{'device-profile.alarm-rules-with-count' | translate:
{count: deviceProfileDataFormGroup.get('alarms').value ?
deviceProfileDataFormGroup.get('alarms').value.length : 0} }}</div>
</mat-panel-title>

View File

@ -15,7 +15,7 @@
limitations under the License.
-->
<div style="min-width: 1000px;">
<div>
<mat-toolbar color="primary">
<h2 translate>device.add-device-text</h2>
<span fxFlex></span>
@ -29,7 +29,7 @@
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div mat-dialog-content>
<mat-horizontal-stepper [linear]="true" #addDeviceWizardStepper (selectionChange)="changeStep($event)">
<mat-horizontal-stepper [linear]="true" [labelPosition]="labelPosition" #addDeviceWizardStepper (selectionChange)="changeStep($event)">
<ng-template matStepperIcon="edit">
<mat-icon>check</mat-icon>
</ng-template>
@ -48,17 +48,49 @@
<mat-label translate>device.label</mat-label>
<input matInput formControlName="label">
</mat-form-field>
<mat-form-field class="mat-block">
<mat-form-field class="mat-block" style="padding-bottom: 14px;">
<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-hint *ngIf="deviceWizardFormGroup.get('transportType').value">
{{deviceTransportTypeHints.get(deviceWizardFormGroup.get('transportType').value) | translate}}
</mat-hint>
<mat-error *ngIf="deviceWizardFormGroup.get('transportType').hasError('required')">
{{ 'device-profile.transport-type-required' | translate }}
</mat-error>
</mat-form-field>
<div fxLayout="row" fxLayoutGap="16px">
<mat-radio-group fxLayout="column" formControlName="addProfileType" fxLayoutAlign="space-around">
<mat-radio-button [value]="0" color="primary">
<span translate>device.wizard.existing-device-profile</span>
</mat-radio-button>
<mat-radio-button [value]="1" color="primary">
<span translate>device.wizard.new-device-profile</span>
</mat-radio-button>
</mat-radio-group>
<div fxLayout="column">
<tb-device-profile-autocomplete
[required]="!createProfile"
[transportType]="deviceWizardFormGroup.get('transportType').value"
formControlName="deviceProfileId"
(deviceProfileChanged)="$event?.transportType ? deviceWizardFormGroup.get('transportType').patchValue($event?.transportType) : {}"
[addNewProfile]="false"
[selectDefaultProfile]="true"
[editProfileEnabled]="false">
</tb-device-profile-autocomplete>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>device-profile.new-device-profile-name</mat-label>
<input matInput formControlName="newDeviceProfileTitle"
[required]="createProfile">
<mat-error *ngIf="deviceWizardFormGroup.get('newDeviceProfileTitle').hasError('required')">
{{ 'device-profile.new-device-profile-name-required' | translate }}
</mat-error>
</mat-form-field>
</div>
</div>
<mat-checkbox formControlName="gateway" style="padding-bottom: 16px;">
{{ 'device.is-gateway' | translate }}
</mat-checkbox>
@ -69,39 +101,7 @@
</fieldset>
</form>
</mat-step>
<mat-step [stepControl]="profileConfigFormGroup">
<form [formGroup]="profileConfigFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{ 'device.wizard.profile-configuration' | translate}}</ng-template>
<mat-radio-group fxLayout="column" fxFlex formControlName="addProfileType">
<mat-radio-button [value]="0" color="primary">
<section>
<span translate>device.wizard.existing-device-profile</span>
<tb-device-profile-autocomplete
[required]="profileConfigFormGroup.get('addProfileType').value === 0"
[transportType]="deviceWizardFormGroup.get('transportType').value"
formControlName="deviceProfileId"
[addNewProfile]="false"
[editProfileEnabled]="false">
</tb-device-profile-autocomplete>
</section>
</mat-radio-button>
<mat-radio-button [value]="1" color="primary">
<section fxLayout="column">
<span translate>device.wizard.new-device-profile</span>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>device-profile.device-profile</mat-label>
<input matInput formControlName="newDeviceProfileTitle"
[required]="profileConfigFormGroup.get('addProfileType').value === 1">
<mat-error *ngIf="profileConfigFormGroup.get('newDeviceProfileTitle').hasError('required')">
{{ 'device-profile.device-profile-required' | translate }}
</mat-error>
</mat-form-field>
</section>
</mat-radio-button>
</mat-radio-group>
</form>
</mat-step>
<mat-step [stepControl]="transportConfigFormGroup" *ngIf="createdProfile">
<mat-step [stepControl]="transportConfigFormGroup" *ngIf="createTransportConfiguration">
<form [formGroup]="transportConfigFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{ 'device-profile.transport-configuration' | translate }}</ng-template>
<tb-device-profile-transport-configuration
@ -110,9 +110,9 @@
</tb-device-profile-transport-configuration>
</form>
</mat-step>
<mat-step [stepControl]="alarmRulesFormGroup" *ngIf="createdProfile">
<mat-step [stepControl]="alarmRulesFormGroup" [optional]="true" *ngIf="createProfile">
<form [formGroup]="alarmRulesFormGroup" style="padding-bottom: 16px;">
<ng-template matStepLabel>{{'device-profile.alarm-rules' | translate:
<ng-template matStepLabel>{{'device-profile.alarm-rules-with-count' | translate:
{count: alarmRulesFormGroup.get('alarms').value ?
alarmRulesFormGroup.get('alarms').value.length : 0} }}</ng-template>
<tb-device-profile-alarms
@ -120,36 +120,50 @@
</tb-device-profile-alarms>
</form>
</mat-step>
<mat-step [stepControl]="specificConfigFormGroup">
<ng-template matStepLabel>{{ 'device.wizard.specific-configuration' | translate }}</ng-template>
<form [formGroup]="specificConfigFormGroup" style="padding-bottom: 16px;">
<mat-step [stepControl]="credentialsFormGroup" [optional]="true">
<ng-template matStepLabel>{{ 'device.credentials' | translate }}</ng-template>
<form [formGroup]="credentialsFormGroup" style="padding-bottom: 16px;">
<mat-checkbox style="padding-bottom: 16px;" formControlName="setCredential">{{ 'device.wizard.add-credential' | translate }}</mat-checkbox>
<tb-device-credentials
[fxShow]="credentialsFormGroup.get('setCredential').value"
formControlName="credential">
</tb-device-credentials>
</form>
</mat-step>
<mat-step [stepControl]="customerFormGroup" [optional]="true">
<ng-template matStepLabel>{{ 'customer.customer' | translate }}</ng-template>
<form [formGroup]="customerFormGroup" style="padding-bottom: 16px;">
<tb-entity-autocomplete
formControlName="customerId"
labelText="device.wizard.customer-to-assign-device"
[entityType]="entityType.CUSTOMER">
</tb-entity-autocomplete>
<mat-checkbox formControlName="setCredential">{{ 'device.wizard.add-credential' | translate }}</mat-checkbox>
<tb-device-credentials
[fxShow]="specificConfigFormGroup.get('setCredential').value"
formControlName="credential">
</tb-device-credentials>
</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">
<div mat-dialog-actions fxLayout="column" fxLayoutAlign="start wrap" fxLayoutGap="8px" style="height: 100px;">
<div fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-raised-button
*ngIf="showNext"
[disabled]="(isLoading$ | async)"
(click)="nextStep()">{{ 'action.next-with-label' | translate:{label: (getFormLabel(this.selectedIndex+1) | translate)} }}</button>
</div>
<div fxFlex fxLayout="row">
<button mat-button
color="primary"
[disabled]="(isLoading$ | async)"
(click)="cancel()">{{ 'action.cancel' | translate }}</button>
<button mat-raised-button
[disabled]="(isLoading$ | async) || selectedForm.invalid"
color="primary"
(click)="nextStep()">{{ nextStepButtonLabel$ | async | translate }}</button>
<span fxFlex></span>
<div fxLayout="row wrap" fxLayoutGap="8px">
<button mat-raised-button *ngIf="selectedIndex > 0"
[disabled]="(isLoading$ | async)"
(click)="previousStep()">{{ 'action.back' | translate }}</button>
<button mat-raised-button
[disabled]="(isLoading$ | async)"
color="primary"
(click)="add()">{{ 'action.add' | translate }}</button>
</div>
</div>
</div>
</div>

View File

@ -13,25 +13,51 @@
* 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;
@import "../../../../../scss/constants";
:host-context(.tb-fullscreen-dialog .mat-dialog-container) {
@media #{$mat-lt-sm} {
.mat-dialog-content {
max-height: 75vh;
}
}
}
:host ::ng-deep {
.mat-dialog-content {
display: flex;
flex-direction: column;
height: 100%;
.mat-stepper-horizontal {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
@media #{$mat-lt-sm} {
.mat-step-label {
white-space: normal;
overflow: visible;
.mat-step-text-label {
overflow: visible;
}
}
}
.mat-horizontal-content-container {
overflow: auto;
height: 450px;
max-height: 100%;
width: 100%;;
overflow-y: auto;
@media #{$mat-gt-sm} {
min-width: 800px;
}
}
.mat-horizontal-stepper-content[aria-expanded=true] {
height: 100%;
form {
height: 100%;
}
}
}
}

View File

@ -26,7 +26,7 @@ import {
createDeviceProfileTransportConfiguration,
DeviceProfile,
DeviceProfileType,
DeviceTransportType,
DeviceTransportType, deviceTransportTypeHintMap,
deviceTransportTypeTranslationMap
} from '@shared/models/device.models';
import { MatHorizontalStepper } from '@angular/material/stepper';
@ -35,11 +35,13 @@ import { BaseData, HasId } from '@shared/models/base-data';
import { EntityType } from '@shared/models/entity-type.models';
import { DeviceProfileService } from '@core/http/device-profile.service';
import { EntityId } from '@shared/models/id/entity-id';
import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
import { Observable, of, Subscription } from 'rxjs';
import { map, mergeMap, tap } from 'rxjs/operators';
import { DeviceService } from '@core/http/device.service';
import { ErrorStateMatcher } from '@angular/material/core';
import { StepperSelectionEvent } from '@angular/cdk/stepper';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { MediaBreakpoints } from '@shared/models/constants';
@Component({
selector: 'tb-device-wizard',
@ -54,9 +56,10 @@ export class DeviceWizardDialogComponent extends
selectedIndex = 0;
nextStepButtonLabel$ = new BehaviorSubject<string>('action.continue');
showNext = true;
createdProfile = false;
createProfile = false;
createTransportConfiguration = false;
entityType = EntityType;
@ -64,15 +67,19 @@ export class DeviceWizardDialogComponent extends
deviceTransportTypeTranslations = deviceTransportTypeTranslationMap;
deviceWizardFormGroup: FormGroup;
deviceTransportTypeHints = deviceTransportTypeHintMap;
profileConfigFormGroup: FormGroup;
deviceWizardFormGroup: FormGroup;
transportConfigFormGroup: FormGroup;
alarmRulesFormGroup: FormGroup;
specificConfigFormGroup: FormGroup;
credentialsFormGroup: FormGroup;
customerFormGroup: FormGroup;
labelPosition = 'end';
private subscriptions: Subscription[] = [];
@ -83,6 +90,7 @@ export class DeviceWizardDialogComponent extends
public dialogRef: MatDialogRef<DeviceWizardDialogComponent, boolean>,
private deviceProfileService: DeviceProfileService,
private deviceService: DeviceService,
private breakpointObserver: BreakpointObserver,
private fb: FormBuilder) {
super(store, router, dialogRef);
this.deviceWizardFormGroup = this.fb.group({
@ -90,33 +98,32 @@ export class DeviceWizardDialogComponent extends
label: [''],
gateway: [false],
transportType: [DeviceTransportType.DEFAULT, Validators.required],
addProfileType: [0],
deviceProfileId: [null, Validators.required],
newDeviceProfileTitle: [{value: null, disabled: true}],
description: ['']
}
);
this.profileConfigFormGroup = this.fb.group({
addProfileType: [0],
deviceProfileId: [null, Validators.required],
newDeviceProfileTitle: [{value: null, disabled: true}]
}
);
this.subscriptions.push(this.profileConfigFormGroup.get('addProfileType').valueChanges.subscribe(
this.subscriptions.push(this.deviceWizardFormGroup.get('addProfileType').valueChanges.subscribe(
(addProfileType: number) => {
if (addProfileType === 0) {
this.profileConfigFormGroup.get('deviceProfileId').setValidators([Validators.required]);
this.profileConfigFormGroup.get('deviceProfileId').enable();
this.profileConfigFormGroup.get('newDeviceProfileTitle').setValidators(null);
this.profileConfigFormGroup.get('newDeviceProfileTitle').disable();
this.profileConfigFormGroup.updateValueAndValidity();
this.createdProfile = false;
this.deviceWizardFormGroup.get('deviceProfileId').setValidators([Validators.required]);
this.deviceWizardFormGroup.get('deviceProfileId').enable();
this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null);
this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable();
this.deviceWizardFormGroup.updateValueAndValidity();
this.createProfile = false;
this.createTransportConfiguration = false;
} else {
this.profileConfigFormGroup.get('deviceProfileId').setValidators(null);
this.profileConfigFormGroup.get('deviceProfileId').disable();
this.profileConfigFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]);
this.profileConfigFormGroup.get('newDeviceProfileTitle').enable();
this.profileConfigFormGroup.updateValueAndValidity();
this.createdProfile = true;
this.deviceWizardFormGroup.get('deviceProfileId').setValidators(null);
this.deviceWizardFormGroup.get('deviceProfileId').disable();
this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]);
this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable();
this.deviceWizardFormGroup.updateValueAndValidity();
this.createProfile = true;
this.createTransportConfiguration = this.deviceWizardFormGroup.get('transportType').value &&
DeviceTransportType.DEFAULT !== this.deviceWizardFormGroup.get('transportType').value;
}
}
));
@ -135,20 +142,37 @@ export class DeviceWizardDialogComponent extends
}
);
this.specificConfigFormGroup = this.fb.group({
customerId: [null],
this.credentialsFormGroup = this.fb.group({
setCredential: [false],
credential: [{value: null, disabled: true}]
}
);
this.subscriptions.push(this.specificConfigFormGroup.get('setCredential').valueChanges.subscribe((value) => {
this.subscriptions.push(this.credentialsFormGroup.get('setCredential').valueChanges.subscribe((value) => {
if (value) {
this.specificConfigFormGroup.get('credential').enable();
this.credentialsFormGroup.get('credential').enable();
} else {
this.specificConfigFormGroup.get('credential').disable();
this.credentialsFormGroup.get('credential').disable();
}
}));
this.customerFormGroup = this.fb.group({
customerId: [null]
}
);
this.labelPosition = this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']) ? 'end' : 'bottom';
this.subscriptions.push(this.breakpointObserver
.observe(MediaBreakpoints['gt-sm'])
.subscribe((state: BreakpointState) => {
if (state.matches) {
this.labelPosition = 'end';
} else {
this.labelPosition = 'bottom';
}
}
));
}
ngOnDestroy() {
@ -171,26 +195,28 @@ export class DeviceWizardDialogComponent extends
}
nextStep(): void {
if (this.selectedIndex < this.maxStepperIndex) {
this.addDeviceWizardStepper.next();
} else {
this.add();
}
this.addDeviceWizardStepper.next();
}
get selectedForm(): FormGroup {
const index = !this.createdProfile && this.selectedIndex === this.maxStepperIndex ? 4 : this.selectedIndex;
getFormLabel(index: number): string {
if (index > 0) {
if (!this.createProfile) {
index += 2;
} else if (!this.createTransportConfiguration) {
index += 1;
}
}
switch (index) {
case 0:
return this.deviceWizardFormGroup;
return 'device.wizard.device-details';
case 1:
return this.profileConfigFormGroup;
return 'device-profile.transport-configuration';
case 2:
return this.transportConfigFormGroup;
return 'device-profile.alarm-rules';
case 3:
return this.alarmRulesFormGroup;
return 'device.credentials';
case 4:
return this.specificConfigFormGroup;
return 'customer.customer';
}
}
@ -201,23 +227,27 @@ export class DeviceWizardDialogComponent extends
private deviceProfileTransportTypeChanged(deviceTransportType: DeviceTransportType): void {
this.transportConfigFormGroup.patchValue(
{transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)});
this.createTransportConfiguration = this.createProfile && deviceTransportType &&
DeviceTransportType.DEFAULT !== deviceTransportType;
}
private add(): void {
this.creatProfile().pipe(
mergeMap(profileId => this.createdDevice(profileId)),
mergeMap(device => this.saveCredential(device))
).subscribe(
(created) => {
this.dialogRef.close(created);
}
);
add(): void {
if (this.allValid()) {
this.createDeviceProfile().pipe(
mergeMap(profileId => this.createDevice(profileId)),
mergeMap(device => this.saveCredentials(device))
).subscribe(
(created) => {
this.dialogRef.close(created);
}
);
}
}
private creatProfile(): Observable<EntityId> {
if (this.profileConfigFormGroup.get('addProfileType').value) {
private createDeviceProfile(): Observable<EntityId> {
if (this.deviceWizardFormGroup.get('addProfileType').value) {
const deviceProfile: DeviceProfile = {
name: this.profileConfigFormGroup.get('newDeviceProfileTitle').value,
name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value,
type: DeviceProfileType.DEFAULT,
transportType: this.deviceWizardFormGroup.get('transportType').value,
profileData: {
@ -229,11 +259,10 @@ export class DeviceWizardDialogComponent extends
return this.deviceProfileService.saveDeviceProfile(deviceProfile).pipe(
map(profile => profile.id),
tap((profileId) => {
this.profileConfigFormGroup.patchValue({
this.deviceWizardFormGroup.patchValue({
deviceProfileId: profileId,
addProfileType: 0
});
this.addDeviceWizardStepper.selectedIndex = 2;
})
);
} else {
@ -241,7 +270,7 @@ export class DeviceWizardDialogComponent extends
}
}
private createdDevice(profileId: EntityId = this.profileConfigFormGroup.get('deviceProfileId').value): Observable<BaseData<HasId>> {
private createDevice(profileId: EntityId = this.deviceWizardFormGroup.get('deviceProfileId').value): Observable<BaseData<HasId>> {
const device = {
name: this.deviceWizardFormGroup.get('name').value,
label: this.deviceWizardFormGroup.get('label').value,
@ -252,21 +281,21 @@ export class DeviceWizardDialogComponent extends
},
customerId: null
};
if (this.specificConfigFormGroup.get('customerId').value) {
if (this.customerFormGroup.get('customerId').value) {
device.customerId = {
entityType: EntityType.CUSTOMER,
id: this.specificConfigFormGroup.get('customerId').value
id: this.customerFormGroup.get('customerId').value
};
}
return this.data.entitiesTableConfig.saveEntity(device);
}
private saveCredential(device: BaseData<HasId>): Observable<boolean> {
if (this.specificConfigFormGroup.get('setCredential').value) {
private saveCredentials(device: BaseData<HasId>): Observable<boolean> {
if (this.credentialsFormGroup.get('setCredential').value) {
return this.deviceService.getDeviceCredentials(device.id.id).pipe(
mergeMap(
(deviceCredentials) => {
const deviceCredentialsValue = {...deviceCredentials, ...this.specificConfigFormGroup.value.credential};
const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential};
return this.deviceService.saveDeviceCredentials(deviceCredentialsValue);
}
),
@ -275,12 +304,28 @@ export class DeviceWizardDialogComponent extends
return of(true);
}
allValid(): boolean {
if (this.addDeviceWizardStepper.steps.find((item, index) => {
if (item.stepControl.invalid) {
item.interacted = true;
this.addDeviceWizardStepper.selectedIndex = index;
return true;
} else {
return false;
}
} )) {
return false;
} else {
return true;
}
}
changeStep($event: StepperSelectionEvent): void {
this.selectedIndex = $event.selectedIndex;
if (this.selectedIndex === this.maxStepperIndex) {
this.nextStepButtonLabel$.next('action.add');
this.showNext = false;
} else {
this.nextStepButtonLabel$.next('action.continue');
this.showNext = true;
}
}
}

View File

@ -296,7 +296,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
name: this.translate.instant('device.add-device-text'),
icon: 'insert_drive_file',
isEnabled: () => true,
onAction: ($event) => this.config.table.addEntity($event)
onAction: ($event) => this.deviceWizard($event)
},
{
name: this.translate.instant('device.import'),
@ -304,12 +304,6 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
isEnabled: () => true,
onAction: ($event) => this.importDevices($event)
},
{
name: this.translate.instant('device.wizard.device-wizard'),
icon: 'library_add',
isEnabled: () => true,
onAction: ($event) => this.deviceWizard($event)
},
);
}
if (deviceScope === 'customer') {

View File

@ -72,6 +72,14 @@ export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, st
]
);
export const deviceTransportTypeHintMap = new Map<DeviceTransportType, string>(
[
[DeviceTransportType.DEFAULT, 'device-profile.transport-type-default-hint'],
[DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt-hint'],
[DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint']
]
);
export const mqttTransportPayloadTypeTranslationMap = new Map<MqttTransportPayloadType, string>(
[
[MqttTransportPayloadType.JSON, 'device-profile.mqtt-device-payload-type-json'],

View File

@ -54,7 +54,8 @@
"share-via": "Share via {{provider}}",
"continue": "Continue",
"discard-changes": "Discard Changes",
"download": "Download"
"download": "Download",
"next-with-label": "Next: {{label}}"
},
"aggregation": {
"aggregation": "Aggregation",
@ -760,8 +761,7 @@
"wizard": {
"device-wizard": "Device Wizard",
"device-details": "Device details",
"profile-configuration": "Profile configuration",
"new-device-profile": "New device profile",
"new-device-profile": "Create new device profile",
"existing-device-profile": "Select existing device profile",
"specific-configuration": "Specific configuration",
"customer-to-assign-device": "Customer to assign the device",
@ -784,6 +784,8 @@
"set-default": "Make device profile default",
"delete": "Delete device profile",
"copyId": "Copy device profile Id",
"new-device-profile-name": "Device profile name",
"new-device-profile-name-required": "Device profile name is required.",
"name": "Name",
"name-required": "Name is required.",
"type": "Profile type",
@ -792,8 +794,11 @@
"transport-type": "Transport type",
"transport-type-required": "Transport type is required.",
"transport-type-default": "Default",
"transport-type-default-hint": "Default transport type",
"transport-type-mqtt": "MQTT",
"transport-type-mqtt-hint": "MQTT transport type",
"transport-type-lwm2m": "LWM2M",
"transport-type-lwm2m-hint": "LWM2M transport type",
"description": "Description",
"default": "Default",
"profile-configuration": "Profile configuration",
@ -824,7 +829,8 @@
"not-valid-multi-character": "Invalid use of a multi-level wildcard character",
"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}})",
"alarm-rules": "Alarm rules",
"alarm-rules-with-count": "Alarm rules ({{count}})",
"no-alarm-rules": "No alarm rules configured",
"add-alarm-rule": "Add alarm rule",
"edit-alarm-rule": "Edit alarm rule",