UI: Added new component copy-device-credentials
This commit is contained in:
parent
986cfe5cc1
commit
205be4e5ce
@ -0,0 +1,26 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<button mat-raised-button
|
||||||
|
ngxClipboard
|
||||||
|
[cbContent]="credential"
|
||||||
|
(cbOnSuccess)="onCopyCredential()"
|
||||||
|
[fxHide]="hideButton"
|
||||||
|
[disabled]="disabled || loading">
|
||||||
|
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
|
||||||
|
<span>{{ buttonLabel }}</span>
|
||||||
|
</button>
|
||||||
@ -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<EntityId>(null);
|
||||||
|
|
||||||
|
private credentials$ = new Subject<DeviceCredentials>();
|
||||||
|
|
||||||
|
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<AppState>,
|
||||||
|
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'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -105,7 +105,7 @@ import { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-conditio
|
|||||||
import { FilterTextComponent } from './filter/filter-text.component';
|
import { FilterTextComponent } from './filter/filter-text.component';
|
||||||
import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component';
|
import { AddDeviceProfileDialogComponent } from './profile/add-device-profile-dialog.component';
|
||||||
import { RuleChainAutocompleteComponent } from './rule-chain/rule-chain-autocomplete.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 { AlarmScheduleComponent } from './profile/alarm/alarm-schedule.component';
|
||||||
import { DeviceWizardDialogComponent } from './wizard/device-wizard-dialog.component';
|
import { DeviceWizardDialogComponent } from './wizard/device-wizard-dialog.component';
|
||||||
import { DeviceCredentialsComponent } from './device/device-credentials.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 { AlarmRuleConditionDialogComponent } from '@home/components/profile/alarm/alarm-rule-condition-dialog.component';
|
||||||
import { DefaultTenantProfileConfigurationComponent } from './profile/tenant/default-tenant-profile-configuration.component';
|
import { DefaultTenantProfileConfigurationComponent } from './profile/tenant/default-tenant-profile-configuration.component';
|
||||||
import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-profile-configuration.component';
|
import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-profile-configuration.component';
|
||||||
|
import { CopyDeviceCredentialsComponent } from './device/copy-device-credentials.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations:
|
declarations:
|
||||||
@ -211,6 +212,7 @@ import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-pro
|
|||||||
AlarmScheduleComponent,
|
AlarmScheduleComponent,
|
||||||
DeviceWizardDialogComponent,
|
DeviceWizardDialogComponent,
|
||||||
DeviceCredentialsComponent,
|
DeviceCredentialsComponent,
|
||||||
|
CopyDeviceCredentialsComponent,
|
||||||
AlarmScheduleDialogComponent,
|
AlarmScheduleDialogComponent,
|
||||||
EditAlarmDetailsDialogComponent
|
EditAlarmDetailsDialogComponent
|
||||||
],
|
],
|
||||||
@ -293,6 +295,7 @@ import { TenantProfileConfigurationComponent } from './profile/tenant/tenant-pro
|
|||||||
RuleChainAutocompleteComponent,
|
RuleChainAutocompleteComponent,
|
||||||
DeviceWizardDialogComponent,
|
DeviceWizardDialogComponent,
|
||||||
DeviceCredentialsComponent,
|
DeviceCredentialsComponent,
|
||||||
|
CopyDeviceCredentialsComponent,
|
||||||
AlarmScheduleInfoComponent,
|
AlarmScheduleInfoComponent,
|
||||||
AlarmScheduleComponent,
|
AlarmScheduleComponent,
|
||||||
AlarmScheduleDialogComponent,
|
AlarmScheduleDialogComponent,
|
||||||
|
|||||||
@ -51,16 +51,17 @@
|
|||||||
ngxClipboard
|
ngxClipboard
|
||||||
(cbOnSuccess)="onDeviceIdCopied($event)"
|
(cbOnSuccess)="onDeviceIdCopied($event)"
|
||||||
[cbContent]="entity?.id?.id"
|
[cbContent]="entity?.id?.id"
|
||||||
|
[disabled]="(isLoading$ | async)"
|
||||||
[fxShow]="!isEdit">
|
[fxShow]="!isEdit">
|
||||||
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
|
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
|
||||||
<span translate>device.copyId</span>
|
<span translate>device.copyId</span>
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button
|
<tb-copy-device-credentials
|
||||||
(click)="copyAccessToken($event)"
|
[fxShow]="!isEdit"
|
||||||
[fxShow]="!isEdit">
|
[disabled]="(isLoading$ | async)"
|
||||||
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
|
[credentials]="componentsData.deviceCredential"
|
||||||
<span translate>device.copyAccessToken</span>
|
[deviceId]="entity?.id">
|
||||||
</button>
|
</tb-copy-device-credentials>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mat-padding" fxLayout="column">
|
<div class="mat-padding" fxLayout="column">
|
||||||
|
|||||||
@ -21,10 +21,9 @@ import { EntityComponent } from '../../components/entity/entity.component';
|
|||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import {
|
import {
|
||||||
createDeviceConfiguration,
|
createDeviceConfiguration,
|
||||||
createDeviceProfileConfiguration, createDeviceTransportConfiguration,
|
createDeviceTransportConfiguration,
|
||||||
DeviceData,
|
DeviceData,
|
||||||
DeviceInfo,
|
DeviceInfo,
|
||||||
DeviceProfileData,
|
|
||||||
DeviceProfileInfo,
|
DeviceProfileInfo,
|
||||||
DeviceProfileType,
|
DeviceProfileType,
|
||||||
DeviceTransportType
|
DeviceTransportType
|
||||||
@ -33,8 +32,6 @@ import { EntityType } from '@shared/models/entity-type.models';
|
|||||||
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
||||||
import { ActionNotificationShow } from '@core/notification/notification.actions';
|
import { ActionNotificationShow } from '@core/notification/notification.actions';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
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';
|
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -46,12 +43,12 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
|
|||||||
|
|
||||||
entityType = EntityType;
|
entityType = EntityType;
|
||||||
|
|
||||||
|
componentsData: any;
|
||||||
|
|
||||||
deviceScope: 'tenant' | 'customer' | 'customer_user';
|
deviceScope: 'tenant' | 'customer' | 'customer_user';
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
protected translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
private deviceService: DeviceService,
|
|
||||||
private clipboardService: ClipboardService,
|
|
||||||
@Inject('entity') protected entityValue: DeviceInfo,
|
@Inject('entity') protected entityValue: DeviceInfo,
|
||||||
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<DeviceInfo>,
|
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<DeviceInfo>,
|
||||||
public fb: FormBuilder) {
|
public fb: FormBuilder) {
|
||||||
@ -60,6 +57,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.deviceScope = this.entitiesTableConfig.componentsData.deviceScope;
|
this.deviceScope = this.entitiesTableConfig.componentsData.deviceScope;
|
||||||
|
this.componentsData = this.entitiesTableConfigValue.componentsData;
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,26 +112,6 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
onDeviceProfileUpdated() {
|
||||||
this.entitiesTableConfig.table.updateData(false);
|
this.entitiesTableConfig.table.updateData(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,6 +63,7 @@ import { DeviceTabsComponent } from '@home/pages/device/device-tabs.component';
|
|||||||
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
|
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
|
||||||
import { DeviceWizardDialogComponent } from '@home/components/wizard/device-wizard-dialog.component';
|
import { DeviceWizardDialogComponent } from '@home/components/wizard/device-wizard-dialog.component';
|
||||||
import { BaseData, HasId } from '@shared/models/base-data';
|
import { BaseData, HasId } from '@shared/models/base-data';
|
||||||
|
import { isDefinedAndNotNull } from '@core/utils';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> {
|
export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> {
|
||||||
@ -115,7 +116,8 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
|
|||||||
const routeParams = route.params;
|
const routeParams = route.params;
|
||||||
this.config.componentsData = {
|
this.config.componentsData = {
|
||||||
deviceScope: route.data.devicesType,
|
deviceScope: route.data.devicesType,
|
||||||
deviceProfileId: null
|
deviceProfileId: null,
|
||||||
|
deviceCredential: null
|
||||||
};
|
};
|
||||||
this.customerId = routeParams.customerId;
|
this.customerId = routeParams.customerId;
|
||||||
return this.store.pipe(select(selectAuthUser), take(1)).pipe(
|
return this.store.pipe(select(selectAuthUser), take(1)).pipe(
|
||||||
@ -479,6 +481,11 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
|
|||||||
deviceId: device.id.id,
|
deviceId: device.id.id,
|
||||||
isReadOnly: this.config.componentsData.deviceScope === 'customer_user'
|
isReadOnly: this.config.componentsData.deviceScope === 'customer_user'
|
||||||
}
|
}
|
||||||
|
}).afterClosed().subscribe(deviceCredential => {
|
||||||
|
if (isDefinedAndNotNull(deviceCredential)) {
|
||||||
|
this.config.table.onEntityUpdated(device);
|
||||||
|
this.config.componentsData.deviceCredential = deviceCredential;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -814,8 +814,10 @@
|
|||||||
"details": "Details",
|
"details": "Details",
|
||||||
"copyId": "Copy device Id",
|
"copyId": "Copy device Id",
|
||||||
"copyAccessToken": "Copy access token",
|
"copyAccessToken": "Copy access token",
|
||||||
|
"copy-mqtt-authentication": "Copy MQTT authentication",
|
||||||
"idCopiedMessage": "Device Id has been copied to clipboard",
|
"idCopiedMessage": "Device Id has been copied to clipboard",
|
||||||
"accessTokenCopiedMessage": "Device access token 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",
|
"assignedToCustomer": "Assigned to customer",
|
||||||
"unable-delete-device-alias-title": "Unable to delete device alias",
|
"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):<br/>{{widgetsList}}",
|
"unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user