device wizard and device component revert changes

This commit is contained in:
Maksym Dudnik 2023-06-30 11:42:36 +03:00
parent bebee3e43b
commit 44d16b2150
7 changed files with 17 additions and 274 deletions

View File

@ -22,7 +22,6 @@ import { DeviceCredentialsComponent } from '@home/components/device/device-crede
import { DeviceCredentialsLwm2mComponent } from '@home/components/device/device-credentials-lwm2m.component'; import { DeviceCredentialsLwm2mComponent } from '@home/components/device/device-credentials-lwm2m.component';
import { DeviceCredentialsLwm2mServerComponent } from '@home/components/device/device-credentials-lwm2m-server.component'; import { DeviceCredentialsLwm2mServerComponent } from '@home/components/device/device-credentials-lwm2m-server.component';
import { DeviceCredentialsMqttBasicComponent } from '@home/components/device/device-credentials-mqtt-basic.component'; import { DeviceCredentialsMqttBasicComponent } from '@home/components/device/device-credentials-mqtt-basic.component';
import { DeviceExampleCommandComponent } from '@home/components/device/device-example-command.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -30,8 +29,7 @@ import { DeviceExampleCommandComponent } from '@home/components/device/device-ex
DeviceCredentialsComponent, DeviceCredentialsComponent,
DeviceCredentialsLwm2mComponent, DeviceCredentialsLwm2mComponent,
DeviceCredentialsLwm2mServerComponent, DeviceCredentialsLwm2mServerComponent,
DeviceCredentialsMqttBasicComponent, DeviceCredentialsMqttBasicComponent
DeviceExampleCommandComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -42,8 +40,7 @@ import { DeviceExampleCommandComponent } from '@home/components/device/device-ex
DeviceCredentialsComponent, DeviceCredentialsComponent,
DeviceCredentialsLwm2mComponent, DeviceCredentialsLwm2mComponent,
DeviceCredentialsLwm2mServerComponent, DeviceCredentialsLwm2mServerComponent,
DeviceCredentialsMqttBasicComponent, DeviceCredentialsMqttBasicComponent
DeviceExampleCommandComponent
] ]
}) })
export class DeviceCredentialsModule { } export class DeviceCredentialsModule { }

View File

@ -1,86 +0,0 @@
<!--
Copyright © 2016-2023 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 mat-dialog-content tb-toast fxLayout="column" toastTarget="dockerCommandDialogContent">
<mat-button-toggle-group [formControl]="protocolCtrl" class="protocol-toggle">
<mat-button-toggle value="mqtt" aria-label="mqtt">
MQTT
</mat-button-toggle>
<mat-button-toggle value="coap" aria-label="coap">
COAP
</mat-button-toggle>
<mat-button-toggle value="http" aria-label="html">
HTTP
</mat-button-toggle>
</mat-button-toggle-group>
<span class="help-title" innerHTML="{{ translate.get('device.telemetry-commands-help-link', {helpLink}) | async }}"></span>
<div class="mat-content" fxLayout="column">
<div class="mat-content" fxLayout="column" *ngIf="protocolCtrl.value === 'mqtt'">
<span>MQTT </span>
<span>{{'device.telemetry-command-setup-step'| translate}} <span [innerHTML]="mqttSetup"></span></span>
<span class="protocol-send-command">{{'device.telemetry-command-send-step'| translate}} </span>
<div fxLayout="row wrap" fxLayoutAlign="start center">
<pre class="tb-highlight" fxFlex><code class="pre-wrap">{{ mqttCode }}</code></pre>
<button mat-icon-button
color="primary"
ngxClipboard
cbContent="{{ mqttCode }}"
(cbOnSuccess)="onDockerCodeCopied()"
matTooltip="{{ 'device.transportCommandCopiedMessage' | translate }}"
matTooltipPosition="above">
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
</button>
</div>
</div>
<div class="mat-content" fxLayout="column" *ngIf="protocolCtrl.value === 'coap'">
<span>COAP </span>
<span>{{'device.telemetry-command-setup-step'| translate}} <span [innerHTML]="coapSetup"></span></span>
<span class="protocol-send-command">{{'device.telemetry-command-send-step-coap'| translate}}</span>
<div fxLayout="row wrap" fxLayoutAlign="start center">
<pre class="tb-highlight" fxFlex><code class="pre-wrap">{{ coapCode }}</code></pre>
<button mat-icon-button
color="primary"
ngxClipboard
cbContent="{{ coapCode }}"
(cbOnSuccess)="onDockerCodeCopied()"
matTooltip="{{ 'device.transportCommandCopiedMessage' | translate }}"
matTooltipPosition="above">
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
</button>
<pre class="tb-highlight" fxFlex="100"><code
class="pre-wrap">JSON example: {{'[{"temperature": 40}, {"isRainy": true}]'}}</code></pre>
</div>
</div>
<div class="mat-content" fxLayout="column" *ngIf="protocolCtrl.value === 'http'">
<span>HTTP </span>
<span>{{'device.telemetry-command-setup-step'| translate}} <span [innerHTML]="httpSetup"></span></span>
<span class="protocol-send-command">{{'device.telemetry-command-send-step'| translate}}</span>
<div fxLayout="row wrpa" fxLayoutAlign="start center">
<pre class="tb-highlight" fxFlex><code class="pre-wrap">{{ httpCode }}</code></pre>
<button mat-icon-button
color="primary"
ngxClipboard
cbContent="{{ httpCode }}"
(cbOnSuccess)="onDockerCodeCopied()"
matTooltip="{{ 'device.transportCommandCopiedMessage' | translate }}"
matTooltipPosition="above">
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
</button>
</div>
</div>
</div>
</div>

View File

@ -1,41 +0,0 @@
/**
* Copyright © 2016-2023 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-button-toggle-group, .protocol-title {
margin-bottom: 20px;
}
span {
margin-bottom: 10px;
}
.protocol-toggle {
width: fit-content;
}
.help-title {
padding-bottom: 5px;
}
.protocol-send-command {
width: 100%;
}
.pre-wrap {
white-space: pre-wrap;
}
}

View File

@ -1,98 +0,0 @@
///
/// Copyright © 2016-2023 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 { Component, Input, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { helpBaseUrl } from '@shared/models/constants';
@Component({
selector: 'tb-device-example-command',
templateUrl: './device-example-command.component.html',
styleUrls: ['./device-example-command.component.scss']
})
export class DeviceExampleCommandComponent implements OnInit {
@Input()
token: string;
helpLink: string = helpBaseUrl + '/docs/reference/protocols/';
mqttCode: string;
coapCode: string;
httpCode: string;
mqttSetup: string;
coapSetup: string;
httpSetup: string;
protocolCtrl: FormControl;
constructor(protected router: Router,
protected store: Store<AppState>,
public translate: TranslateService) {
}
ngOnInit(): void {
const HOST = window.location.hostname;
this.mqttCode = `mosquitto_pub -d -q 1 -h ${HOST} -t "v1/devices/me/telemetry" -u "${this.token}" -m "{"temperature":42}"`;
this.coapCode = `cat telemetry-data.json | coap post coap://${HOST}/api/v1/${this.token}/telemetry`;
this.httpCode = `curl -v -X POST --data "{"temperature":42,"humidity":73}" http://${HOST}/api/v1/${this.token}/telemetry --header "Content-Type:application/json"`;
this.protocolCtrl = new FormControl('mqtt');
const mqttLink = '<a href="https://thingsboard.io/docs/getting-started-guides/helloworld/?connectdevice=mqtt-windows"> Mqtt Guide</a>';
// @ts-ignore
const platform = window.navigator?.userAgentData?.platform || window.navigator.platform,
macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'];
if (macosPlatforms.indexOf(platform) !== -1) {
this.mqttSetup = 'brew install mosquitto-clients';
this.coapSetup = 'npm install coap-cli -g';
this.httpSetup = 'brew install curl';
} else if (windowsPlatforms.indexOf(platform) !== -1) {
this.mqttSetup = mqttLink;
this.coapSetup = 'npm install coap-cli -g';
this.httpSetup = 'not required, available by default in windows 10+';
} else if (/Linux/.test(platform)) {
this.mqttSetup = 'sudo apt-get install mosquitto-clients';
this.coapSetup = 'npm install coap-cli -g';
this.httpSetup = 'sudo apt-get install curl';
}
}
onDockerCodeCopied() {
this.store.dispatch(new ActionNotificationShow(
{
message: this.translate.instant('gateway.command-copied-message'),
type: 'success',
target: 'dockerCommandDialogContent',
duration: 1200,
verticalPosition: 'bottom',
horizontalPosition: 'left'
}));
}
}

View File

@ -29,7 +29,7 @@
</mat-progress-bar> </mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div> <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div mat-dialog-content> <div mat-dialog-content>
<mat-horizontal-stepper [linear]="true" [labelPosition]="labelPosition" #addDeviceWizardStepper (selectionChange)="changeStep($event)" *ngIf="!deviceCredentials"> <mat-horizontal-stepper [linear]="true" [labelPosition]="labelPosition" #addDeviceWizardStepper (selectionChange)="changeStep($event)">
<ng-template matStepperIcon="edit"> <ng-template matStepperIcon="edit">
<mat-icon>check</mat-icon> <mat-icon>check</mat-icon>
</ng-template> </ng-template>
@ -178,17 +178,9 @@
</form> </form>
</mat-step> </mat-step>
</mat-horizontal-stepper> </mat-horizontal-stepper>
<div *ngIf="deviceCredentials" class="commands-container">
<tb-gateway-command *ngIf="device?.additionalInfo?.gateway"
[token]="deviceCredentials.credentialsId">
</tb-gateway-command>
<tb-device-example-command *ngIf="!device?.additionalInfo?.gateway"
[token]="deviceCredentials.credentialsId">
</tb-device-example-command>
</div>
</div> </div>
<div mat-dialog-actions style="padding: 0"> <div mat-dialog-actions style="padding: 0">
<div class="dialog-actions-row" fxFlex fxLayout="row" fxLayoutAlign="end center" *ngIf="!deviceCredentials"> <div class="dialog-actions-row" fxFlex fxLayout="row" fxLayoutAlign="end center">
<button mat-stroked-button *ngIf="selectedIndex > 0" <button mat-stroked-button *ngIf="selectedIndex > 0"
[disabled]="(isLoading$ | async)" [disabled]="(isLoading$ | async)"
(click)="previousStep()">{{ 'action.back' | translate }}</button> (click)="previousStep()">{{ 'action.back' | translate }}</button>
@ -203,11 +195,10 @@
<div class="dialog-actions-row" fxFlex fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="end center"> <div class="dialog-actions-row" fxFlex fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="end center">
<button mat-button <button mat-button
[disabled]="(isLoading$ | async)" [disabled]="(isLoading$ | async)"
*ngIf="!deviceCredentials"
(click)="cancel()">{{ 'action.cancel' | translate }}</button> (click)="cancel()">{{ 'action.cancel' | translate }}</button>
<button mat-raised-button <button mat-raised-button
[disabled]="(isLoading$ | async)" [disabled]="(isLoading$ | async)"
color="primary" color="primary"
(click)="add()">{{ (deviceCredentials ? 'action.close': 'action.add') | translate }}</button> (click)="add()">{{ 'action.add' | translate }}</button>
</div> </div>
</div> </div>

View File

@ -37,10 +37,6 @@
} }
:host ::ng-deep { :host ::ng-deep {
.commands-container {
padding: 24px;
}
.mat-mdc-dialog-content { .mat-mdc-dialog-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -24,8 +24,6 @@ import { Router } from '@angular/router';
import { import {
createDeviceProfileConfiguration, createDeviceProfileConfiguration,
createDeviceProfileTransportConfiguration, createDeviceProfileTransportConfiguration,
Device,
DeviceCredentials,
DeviceProfile, DeviceProfile,
DeviceProfileInfo, DeviceProfileInfo,
DeviceProfileType, DeviceProfileType,
@ -59,9 +57,9 @@ import { deepTrim } from '@core/utils';
styleUrls: ['./device-wizard-dialog.component.scss'] styleUrls: ['./device-wizard-dialog.component.scss']
}) })
export class DeviceWizardDialogComponent extends export class DeviceWizardDialogComponent extends
DialogComponent<DeviceWizardDialogComponent, Device> implements OnDestroy, ErrorStateMatcher { DialogComponent<DeviceWizardDialogComponent, boolean> implements OnDestroy, ErrorStateMatcher {
@ViewChild('addDeviceWizardStepper') addDeviceWizardStepper: MatStepper; @ViewChild('addDeviceWizardStepper', {static: true}) addDeviceWizardStepper: MatStepper;
selectedIndex = 0; selectedIndex = 0;
@ -71,7 +69,7 @@ export class DeviceWizardDialogComponent extends
entityType = EntityType; entityType = EntityType;
deviceTransportTypes = Object.values(DeviceTransportType) as DeviceTransportType[]; deviceTransportTypes = Object.values(DeviceTransportType);
deviceTransportTypeTranslations = deviceTransportTypeTranslationMap; deviceTransportTypeTranslations = deviceTransportTypeTranslationMap;
@ -93,10 +91,6 @@ export class DeviceWizardDialogComponent extends
serviceType = ServiceType.TB_RULE_ENGINE; serviceType = ServiceType.TB_RULE_ENGINE;
device: Device;
deviceCredentials: DeviceCredentials;
private subscriptions: Subscription[] = []; private subscriptions: Subscription[] = [];
private currentDeviceProfileTransportType = DeviceTransportType.DEFAULT; private currentDeviceProfileTransportType = DeviceTransportType.DEFAULT;
@ -104,7 +98,7 @@ export class DeviceWizardDialogComponent extends
protected router: Router, protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: AddEntityDialogData<BaseData<EntityId>>, @Inject(MAT_DIALOG_DATA) public data: AddEntityDialogData<BaseData<EntityId>>,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher, @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
public dialogRef: MatDialogRef<DeviceWizardDialogComponent, Device>, public dialogRef: MatDialogRef<DeviceWizardDialogComponent, boolean>,
private deviceProfileService: DeviceProfileService, private deviceProfileService: DeviceProfileService,
private deviceService: DeviceService, private deviceService: DeviceService,
private breakpointObserver: BreakpointObserver, private breakpointObserver: BreakpointObserver,
@ -269,15 +263,13 @@ export class DeviceWizardDialogComponent extends
} }
add(): void { add(): void {
if (this.deviceCredentials) { if (this.allValid()) {
this.dialogRef.close(this.device);
} else if (this.allValid()) {
this.createDeviceProfile().pipe( this.createDeviceProfile().pipe(
mergeMap(profileId => this.createDevice(profileId)), mergeMap(profileId => this.createDevice(profileId)),
mergeMap(device => this.saveCredentials(device)), mergeMap(device => this.saveCredentials(device))
).subscribe( ).subscribe(
(device) => { (created) => {
this.device = device; this.dialogRef.close(created);
} }
); );
} }
@ -334,7 +326,7 @@ export class DeviceWizardDialogComponent extends
} }
} }
private createDevice(profileId): Observable<Device> { private createDevice(profileId): Observable<BaseData<HasId>> {
const device = { const device = {
name: this.deviceWizardFormGroup.get('name').value, name: this.deviceWizardFormGroup.get('name').value,
label: this.deviceWizardFormGroup.get('label').value, label: this.deviceWizardFormGroup.get('label').value,
@ -357,16 +349,15 @@ export class DeviceWizardDialogComponent extends
this.addDeviceWizardStepper.selectedIndex = 0; this.addDeviceWizardStepper.selectedIndex = 0;
return throwError(e); return throwError(e);
}) })
) as Observable<Device>; );
} }
private saveCredentials(device: Device): Observable<Device> { private saveCredentials(device: BaseData<HasId>): Observable<boolean> {
if (this.credentialsFormGroup.get('setCredential').value) { if (this.credentialsFormGroup.get('setCredential').value) {
return this.deviceService.getDeviceCredentials(device.id.id).pipe( return this.deviceService.getDeviceCredentials(device.id.id).pipe(
mergeMap( mergeMap(
(deviceCredentials) => { (deviceCredentials) => {
const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential}; const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential};
this.deviceCredentials = deviceCredentialsValue;
return this.deviceService.saveDeviceCredentials(deviceCredentialsValue).pipe( return this.deviceService.saveDeviceCredentials(deviceCredentialsValue).pipe(
catchError(e => { catchError(e => {
this.addDeviceWizardStepper.selectedIndex = 1; this.addDeviceWizardStepper.selectedIndex = 1;
@ -379,14 +370,7 @@ export class DeviceWizardDialogComponent extends
); );
} }
), ),
map(() => device)); map(() => true));
} else {
return this.deviceService.getDeviceCredentials(device.id.id).pipe(
map((deviceCredentials) => {
this.deviceCredentials = deviceCredentials;
return device;
})
);
} }
} }