From 205be4e5cea74108564a6f4fd38973d1cb588713 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 23 Nov 2020 12:13:05 +0200 Subject: [PATCH 1/4] UI: Added new component copy-device-credentials --- .../copy-device-credentials.component.html | 26 ++++ .../copy-device-credentials.component.ts | 128 ++++++++++++++++++ .../home/components/home-components.module.ts | 5 +- .../home/pages/device/device.component.html | 13 +- .../home/pages/device/device.component.ts | 30 +--- .../device/devices-table-config.resolver.ts | 9 +- .../assets/locale/locale.constant-en_US.json | 2 + 7 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.html create mode 100644 ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.ts diff --git a/ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.html new file mode 100644 index 0000000000..77c3d10c4a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.html @@ -0,0 +1,26 @@ + + diff --git a/ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.ts b/ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.ts new file mode 100644 index 0000000000..99b4a82960 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/device/copy-device-credentials.component.ts @@ -0,0 +1,128 @@ +/// +/// 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 { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { EntityId } from '@shared/models/id/entity-id'; +import { DeviceService } from '@core/http/device.service'; +import { DeviceCredentials, DeviceCredentialsType } from '@shared/models/device.models'; +import { isDefinedAndNotNull, isEqual } from '@core/utils'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { distinctUntilChanged, filter, mergeMap, tap } from 'rxjs/operators'; +import { EntityType } from '@shared/models/entity-type.models'; +import { ActionNotificationShow } from '@core/notification/notification.actions'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'tb-copy-device-credentials', + templateUrl: './copy-device-credentials.component.html', + styleUrls: [] +}) +export class CopyDeviceCredentialsComponent implements OnDestroy { + + private deviceId$ = new BehaviorSubject(null); + + private credentials$ = new Subject(); + + private tooltipMessage: string; + + public hideButton = true; + + public credential: string; + + public loading = false; + + public buttonLabel: string; + + @Input() + set deviceId(deviceId: EntityId) { + this.deviceId$.next(deviceId); + } + + @Input() disabled: boolean; + + @Input() + set credentials(credential: DeviceCredentials) { + this.credentials$.next(credential); + } + + constructor(private store: Store, + private translate: TranslateService, + private deviceService: DeviceService + ) { + this.deviceId$.pipe( + filter(device => isDefinedAndNotNull(device) && device.entityType === EntityType.DEVICE), + distinctUntilChanged((prev, curr) => prev.id === curr.id), + tap(() => this.loading = true), + mergeMap(device => this.deviceService.getDeviceCredentials(device.id)) + ).subscribe(deviceCredentials => { + this.processingValue(deviceCredentials); + this.loading = false; + }); + + this.credentials$.pipe( + filter(credential => isDefinedAndNotNull(credential)), + distinctUntilChanged((prev, curr) => isEqual(prev, curr)) + ).subscribe(deviceCredentials => { + console.warn(deviceCredentials); + this.processingValue(deviceCredentials); + }); + } + + ngOnDestroy(): void { + this.deviceId$.unsubscribe(); + this.credentials$.unsubscribe(); + } + + private processingValue(credential: DeviceCredentials): void { + switch (credential.credentialsType) { + case DeviceCredentialsType.ACCESS_TOKEN: + this.hideButton = false; + this.credential = credential.credentialsId; + this.buttonLabel = this.translate.instant('device.copyAccessToken'); + this.tooltipMessage = this.translate.instant('device.accessTokenCopiedMessage'); + break; + case DeviceCredentialsType.MQTT_BASIC: + this.hideButton = false; + this.credential = this.convertObjectToString(JSON.parse(credential.credentialsValue)); + this.buttonLabel = this.translate.instant('device.copy-mqtt-authentication'); + this.tooltipMessage = this.translate.instant('device.mqtt-authentication-copied-message'); + break; + default: + this.hideButton = true; + this.credential = null; + this.buttonLabel = ''; + this.tooltipMessage = ''; + } + } + + private convertObjectToString(obj: object): string { + Object.keys(obj).forEach(k => (!obj[k] && obj[k] !== undefined) && delete obj[k]); + return JSON.stringify(obj).replace(/"([^"]+)":/g, '$1:'); + } + + onCopyCredential() { + this.store.dispatch(new ActionNotificationShow( + { + message: this.tooltipMessage, + type: 'success', + duration: 750, + verticalPosition: 'bottom', + horizontalPosition: 'right' + })); + } +} diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index ec7ccea660..54d15c1ee1 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -105,7 +105,7 @@ import { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-conditio import { FilterTextComponent } from './filter/filter-text.component'; import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component'; import { RuleChainAutocompleteComponent } from './rule-chain/rule-chain-autocomplete.component'; -import { DeviceProfileProvisionConfigurationComponent } from "./profile/device-profile-provision-configuration.component"; +import { DeviceProfileProvisionConfigurationComponent } from './profile/device-profile-provision-configuration.component'; import { AlarmScheduleComponent } from './profile/alarm/alarm-schedule.component'; import { DeviceWizardDialogComponent } from './wizard/device-wizard-dialog.component'; import { DeviceCredentialsComponent } from './device/device-credentials.component'; @@ -115,6 +115,7 @@ import { EditAlarmDetailsDialogComponent } from './profile/alarm/edit-alarm-deta import { AlarmRuleConditionDialogComponent } from '@home/components/profile/alarm/alarm-rule-condition-dialog.component'; import { DefaultTenantProfileConfigurationComponent } from './profile/tenant/default-tenant-profile-configuration.component'; import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-profile-configuration.component'; +import { CopyDeviceCredentialsComponent } from './device/copy-device-credentials.component'; @NgModule({ declarations: @@ -211,6 +212,7 @@ import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-pro AlarmScheduleComponent, DeviceWizardDialogComponent, DeviceCredentialsComponent, + CopyDeviceCredentialsComponent, AlarmScheduleDialogComponent, EditAlarmDetailsDialogComponent ], @@ -293,6 +295,7 @@ import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-pro RuleChainAutocompleteComponent, DeviceWizardDialogComponent, DeviceCredentialsComponent, + CopyDeviceCredentialsComponent, AlarmScheduleInfoComponent, AlarmScheduleComponent, AlarmScheduleDialogComponent, diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index e9371b4708..d781aa1373 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -51,16 +51,17 @@ ngxClipboard (cbOnSuccess)="onDeviceIdCopied($event)" [cbContent]="entity?.id?.id" + [disabled]="(isLoading$ | async)" [fxShow]="!isEdit"> device.copyId - + +
diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 833919eb78..74503bfddb 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -21,10 +21,9 @@ import { EntityComponent } from '../../components/entity/entity.component'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { createDeviceConfiguration, - createDeviceProfileConfiguration, createDeviceTransportConfiguration, + createDeviceTransportConfiguration, DeviceData, DeviceInfo, - DeviceProfileData, DeviceProfileInfo, DeviceProfileType, DeviceTransportType @@ -33,8 +32,6 @@ import { EntityType } from '@shared/models/entity-type.models'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { TranslateService } from '@ngx-translate/core'; -import { DeviceService } from '@core/http/device.service'; -import { ClipboardService } from 'ngx-clipboard'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; @Component({ @@ -46,12 +43,12 @@ export class DeviceComponent extends EntityComponent { entityType = EntityType; + componentsData: any; + deviceScope: 'tenant' | 'customer' | 'customer_user'; constructor(protected store: Store, protected translate: TranslateService, - private deviceService: DeviceService, - private clipboardService: ClipboardService, @Inject('entity') protected entityValue: DeviceInfo, @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig, public fb: FormBuilder) { @@ -60,6 +57,7 @@ export class DeviceComponent extends EntityComponent { ngOnInit() { this.deviceScope = this.entitiesTableConfig.componentsData.deviceScope; + this.componentsData = this.entitiesTableConfigValue.componentsData; super.ngOnInit(); } @@ -114,26 +112,6 @@ export class DeviceComponent extends EntityComponent { })); } - copyAccessToken($event) { - if (this.entity.id) { - this.deviceService.getDeviceCredentials(this.entity.id.id, true).subscribe( - (deviceCredentials) => { - const credentialsId = deviceCredentials.credentialsId; - if (this.clipboardService.copyFromContent(credentialsId)) { - this.store.dispatch(new ActionNotificationShow( - { - message: this.translate.instant('device.accessTokenCopiedMessage'), - type: 'success', - duration: 750, - verticalPosition: 'bottom', - horizontalPosition: 'right' - })); - } - } - ); - } - } - onDeviceProfileUpdated() { this.entitiesTableConfig.table.updateData(false); } diff --git a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts index 0aaf8e62e7..60dffcc5fe 100644 --- a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts @@ -63,6 +63,7 @@ import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component'; import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; import { DeviceWizardDialogComponent } from '@home/components/wizard/device-wizard-dialog.component'; import { BaseData, HasId } from '@shared/models/base-data'; +import { isDefinedAndNotNull } from '@core/utils'; @Injectable() export class DevicesTableConfigResolver implements Resolve> { @@ -115,7 +116,8 @@ export class DevicesTableConfigResolver implements Resolve { + if (isDefinedAndNotNull(deviceCredential)) { + this.config.table.onEntityUpdated(device); + this.config.componentsData.deviceCredential = deviceCredential; + } }); } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index cddc73415e..6c51d65424 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -814,8 +814,10 @@ "details": "Details", "copyId": "Copy device Id", "copyAccessToken": "Copy access token", + "copy-mqtt-authentication": "Copy MQTT authentication", "idCopiedMessage": "Device Id has been copied to clipboard", "accessTokenCopiedMessage": "Device access token has been copied to clipboard", + "mqtt-authentication-copied-message": "Device MQTT authentication has been copied to clipboard", "assignedToCustomer": "Assigned to customer", "unable-delete-device-alias-title": "Unable to delete device alias", "unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", From e1b9124ee48de2d9ef3be9dcf9494ffa4af939fe Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 23 Nov 2020 12:17:20 +0200 Subject: [PATCH 2/4] Refactoring --- .../modules/home/pages/device/devices-table-config.resolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts index 60dffcc5fe..1aefffa184 100644 --- a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts @@ -483,7 +483,6 @@ export class DevicesTableConfigResolver implements Resolve { if (isDefinedAndNotNull(deviceCredential)) { - this.config.table.onEntityUpdated(device); this.config.componentsData.deviceCredential = deviceCredential; } }); From 7f9bbb24047095d65ba769905d7e0debd397eebb Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 23 Nov 2020 12:19:34 +0200 Subject: [PATCH 3/4] Revert change after merge --- .../home/components/home-components.module.ts | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 27992d981a..113f4ae4bb 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -81,35 +81,35 @@ import { FilterSelectComponent } from '@home/components/filter/filter-select.com import { FiltersEditComponent } from '@home/components/filter/filters-edit.component'; import { FiltersEditPanelComponent } from '@home/components/filter/filters-edit-panel.component'; import { UserFilterDialogComponent } from '@home/components/filter/user-filter-dialog.component'; -import { FilterUserInfoComponent } from './filter/filter-user-info.component'; -import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.component'; -import { FilterPredicateValueComponent } from './filter/filter-predicate-value.component'; -import { TenantProfileAutocompleteComponent } from './profile/tenant-profile-autocomplete.component'; -import { TenantProfileComponent } from './profile/tenant-profile.component'; -import { TenantProfileDialogComponent } from './profile/tenant-profile-dialog.component'; -import { TenantProfileDataComponent } from './profile/tenant-profile-data.component'; -import { DefaultDeviceProfileConfigurationComponent } from './profile/device/default-device-profile-configuration.component'; -import { DeviceProfileConfigurationComponent } from './profile/device/device-profile-configuration.component'; -import { DeviceProfileComponent } from './profile/device-profile.component'; -import { DefaultDeviceProfileTransportConfigurationComponent } from './profile/device/default-device-profile-transport-configuration.component'; -import { DeviceProfileTransportConfigurationComponent } from './profile/device/device-profile-transport-configuration.component'; -import { DeviceProfileDialogComponent } from './profile/device-profile-dialog.component'; -import { DeviceProfileAutocompleteComponent } from './profile/device-profile-autocomplete.component'; -import { MqttDeviceProfileTransportConfigurationComponent } from './profile/device/mqtt-device-profile-transport-configuration.component'; -import { Lwm2mDeviceProfileTransportConfigurationComponent } from './profile/device/lwm2m-device-profile-transport-configuration.component'; -import { DeviceProfileAlarmsComponent } from './profile/alarm/device-profile-alarms.component'; -import { DeviceProfileAlarmComponent } from './profile/alarm/device-profile-alarm.component'; -import { CreateAlarmRulesComponent } from './profile/alarm/create-alarm-rules.component'; -import { AlarmRuleComponent } from './profile/alarm/alarm-rule.component'; -import { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-condition.component'; -import { FilterTextComponent } from './filter/filter-text.component'; -import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component'; -import { RuleChainAutocompleteComponent } from './rule-chain/rule-chain-autocomplete.component'; -import { DeviceProfileProvisionConfigurationComponent } from './profile/device-profile-provision-configuration.component'; -import { AlarmScheduleComponent } from './profile/alarm/alarm-schedule.component'; -import { DeviceWizardDialogComponent } from './wizard/device-wizard-dialog.component'; -import { DeviceCredentialsComponent } from './device/device-credentials.component'; -import { AlarmScheduleInfoComponent } from './profile/alarm/alarm-schedule-info.component'; +import { FilterUserInfoComponent } from '@home/components/filter/filter-user-info.component'; +import { FilterUserInfoDialogComponent } from '@home/components/filter/filter-user-info-dialog.component'; +import { FilterPredicateValueComponent } from '@home/components/filter/filter-predicate-value.component'; +import { TenantProfileAutocompleteComponent } from '@home/components/profile/tenant-profile-autocomplete.component'; +import { TenantProfileComponent } from '@home/components/profile/tenant-profile.component'; +import { TenantProfileDialogComponent } from '@home/components/profile/tenant-profile-dialog.component'; +import { TenantProfileDataComponent } from '@home/components/profile/tenant-profile-data.component'; +import { DefaultDeviceProfileConfigurationComponent } from '@home/components/profile/device/default-device-profile-configuration.component'; +import { DeviceProfileConfigurationComponent } from '@home/components/profile/device/device-profile-configuration.component'; +import { DeviceProfileComponent } from '@home/components/profile/device-profile.component'; +import { DefaultDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/default-device-profile-transport-configuration.component'; +import { DeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/device-profile-transport-configuration.component'; +import { DeviceProfileDialogComponent } from '@home/components/profile/device-profile-dialog.component'; +import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component'; +import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component'; +import { Lwm2mDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/lwm2m-device-profile-transport-configuration.component'; +import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component'; +import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component'; +import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component'; +import { AlarmRuleComponent } from '@home/components/profile/alarm/alarm-rule.component'; +import { AlarmRuleConditionComponent } from '@home/components/profile/alarm/alarm-rule-condition.component'; +import { FilterTextComponent } from '@home/components/filter/filter-text.component'; +import { AddDeviceProfileDialogComponent } from '@home/components/profile/add-device-profile-dialog.component'; +import { RuleChainAutocompleteComponent } from '@home/components/rule-chain/rule-chain-autocomplete.component'; +import { DeviceProfileProvisionConfigurationComponent } from '@home/components/profile/device-profile-provision-configuration.component'; +import { AlarmScheduleComponent } from '@home/components/profile/alarm/alarm-schedule.component'; +import { DeviceWizardDialogComponent } from '@home/components/wizard/device-wizard-dialog.component'; +import { DeviceCredentialsComponent } from '@home/components/device/device-credentials.component'; +import { AlarmScheduleInfoComponent } from '@home/components/profile/alarm/alarm-schedule-info.component'; import { AlarmScheduleDialogComponent } from '@home/components/profile/alarm/alarm-schedule-dialog.component'; import { EditAlarmDetailsDialogComponent } from '@home/components/profile/alarm/edit-alarm-details-dialog.component'; import { AlarmRuleConditionDialogComponent } from '@home/components/profile/alarm/alarm-rule-condition-dialog.component'; From 5436316d1e075252bbf2c8136c4f4c0c94c4e1d5 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 23 Nov 2020 13:02:10 +0200 Subject: [PATCH 4/4] Fixed updated button --- .../modules/home/pages/device/devices-table-config.resolver.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts index 1aefffa184..b04bf13d44 100644 --- a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts @@ -484,6 +484,7 @@ export class DevicesTableConfigResolver implements Resolve { if (isDefinedAndNotNull(deviceCredential)) { this.config.componentsData.deviceCredential = deviceCredential; + this.config.table.onEntityUpdated(device); } }); }