79 changed files with 6947 additions and 8718 deletions
@ -1,29 +0,0 @@ |
|||
/** |
|||
* 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. |
|||
*/ |
|||
package org.thingsboard.server.common.msg.kv; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
|
|||
import org.thingsboard.server.common.data.kv.AttributeKey; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
|
|||
public interface AttributesKVMsg extends Serializable { |
|||
|
|||
List<AttributeKvEntry> getClientAttributes(); |
|||
List<AttributeKvEntry> getSharedAttributes(); |
|||
List<AttributeKey> getDeletedAttributes(); |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
/** |
|||
* 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. |
|||
*/ |
|||
package org.thingsboard.server.common.msg.kv; |
|||
|
|||
import lombok.AccessLevel; |
|||
import lombok.Data; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.kv.AttributeKey; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
@Data |
|||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) |
|||
public class BasicAttributeKVMsg implements AttributesKVMsg { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private final List<AttributeKvEntry> clientAttributes; |
|||
private final List<AttributeKvEntry> sharedAttributes; |
|||
private final List<AttributeKey> deletedAttributes; |
|||
|
|||
public static BasicAttributeKVMsg fromClient(List<AttributeKvEntry> attributes) { |
|||
return new BasicAttributeKVMsg(attributes, Collections.emptyList(), Collections.emptyList()); |
|||
} |
|||
|
|||
public static BasicAttributeKVMsg fromShared(List<AttributeKvEntry> attributes) { |
|||
return new BasicAttributeKVMsg(Collections.emptyList(), attributes, Collections.emptyList()); |
|||
} |
|||
|
|||
public static BasicAttributeKVMsg from(List<AttributeKvEntry> client, List<AttributeKvEntry> shared) { |
|||
return new BasicAttributeKVMsg(client, shared, Collections.emptyList()); |
|||
} |
|||
|
|||
public static AttributesKVMsg fromDeleted(List<AttributeKey> shared) { |
|||
return new BasicAttributeKVMsg(Collections.emptyList(), Collections.emptyList(), shared); |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,66 @@ |
|||
///
|
|||
/// 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 { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { PageLink } from '@shared/models/page/page-link'; |
|||
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
|||
import { Observable } from 'rxjs'; |
|||
import { PageData } from '@shared/models/page/page-data'; |
|||
import { DeviceProfile, DeviceProfileInfo } from '@shared/models/device.models'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class DeviceProfileService { |
|||
|
|||
constructor( |
|||
private http: HttpClient |
|||
) { } |
|||
|
|||
public getDeviceProfiles(pageLink: PageLink, config?: RequestConfig): Observable<PageData<DeviceProfile>> { |
|||
return this.http.get<PageData<DeviceProfile>>(`/api/deviceProfiles${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getDeviceProfile(deviceProfileId: string, config?: RequestConfig): Observable<DeviceProfile> { |
|||
return this.http.get<DeviceProfile>(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public saveDeviceProfile(deviceProfile: DeviceProfile, config?: RequestConfig): Observable<DeviceProfile> { |
|||
return this.http.post<DeviceProfile>('/api/deviceProfile', deviceProfile, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public deleteDeviceProfile(deviceProfileId: string, config?: RequestConfig) { |
|||
return this.http.delete(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public setDefaultDeviceProfile(deviceProfileId: string, config?: RequestConfig): Observable<DeviceProfile> { |
|||
return this.http.post<DeviceProfile>(`/api/deviceProfile/${deviceProfileId}/default`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getDefaultDeviceProfileInfo(config?: RequestConfig): Observable<DeviceProfileInfo> { |
|||
return this.http.get<DeviceProfileInfo>('/api/deviceProfileInfo/default', defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getDeviceProfileInfo(deviceProfileId: string, config?: RequestConfig): Observable<DeviceProfileInfo> { |
|||
return this.http.get<DeviceProfileInfo>(`/api/deviceProfileInfo/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getDeviceProfileInfos(pageLink: PageLink, config?: RequestConfig): Observable<PageData<DeviceProfileInfo>> { |
|||
return this.http.get<PageData<DeviceProfileInfo>>(`/api/deviceProfileInfos${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
<!-- |
|||
|
|||
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 [formGroup]="deviceProfileDataFormGroup"> |
|||
<mat-accordion multi="true"> |
|||
<mat-expansion-panel [expanded]="true"> |
|||
<mat-expansion-panel-header> |
|||
<mat-panel-title> |
|||
<div translate>device-profile.profile-configuration</div> |
|||
</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
<tb-device-profile-configuration |
|||
formControlName="configuration" |
|||
required> |
|||
</tb-device-profile-configuration> |
|||
</mat-expansion-panel> |
|||
<mat-expansion-panel [expanded]="true"> |
|||
<mat-expansion-panel-header> |
|||
<mat-panel-title> |
|||
<div translate>device-profile.transport-configuration</div> |
|||
</mat-panel-title> |
|||
</mat-expansion-panel-header> |
|||
TODO |
|||
</mat-expansion-panel> |
|||
</mat-accordion> |
|||
</div> |
|||
@ -0,0 +1,92 @@ |
|||
///
|
|||
/// 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, forwardRef, Input, OnInit } from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@app/core/core.state'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { DeviceProfileData } from '@shared/models/device.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-device-profile-data', |
|||
templateUrl: './device-profile-data.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => DeviceProfileDataComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class DeviceProfileDataComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
deviceProfileDataFormGroup: FormGroup; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.deviceProfileDataFormGroup = this.fb.group({ |
|||
configuration: [null, Validators.required] |
|||
}); |
|||
this.deviceProfileDataFormGroup.valueChanges.subscribe(() => { |
|||
this.updateModel(); |
|||
}); |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.deviceProfileDataFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.deviceProfileDataFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: DeviceProfileData | null): void { |
|||
this.deviceProfileDataFormGroup.patchValue({configuration: value?.configuration}, {emitEvent: false}); |
|||
} |
|||
|
|||
private updateModel() { |
|||
let deviceProfileData: DeviceProfileData = null; |
|||
if (this.deviceProfileDataFormGroup.valid) { |
|||
deviceProfileData = this.deviceProfileDataFormGroup.getRawValue(); |
|||
} |
|||
this.propagateChange(deviceProfileData); |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
<!-- |
|||
|
|||
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 class="tb-details-buttons" fxLayout.xs="column" *ngIf="!standalone"> |
|||
<button mat-raised-button color="primary" |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="onEntityAction($event, 'setDefault')" |
|||
[fxShow]="!isEdit && !entity?.default"> |
|||
{{'device-profile.set-default' | translate }} |
|||
</button> |
|||
<button mat-raised-button color="primary" |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="onEntityAction($event, 'delete')" |
|||
[fxShow]="!hideDelete() && !isEdit"> |
|||
{{'device-profile.delete' | translate }} |
|||
</button> |
|||
<div fxLayout="row" fxLayout.xs="column"> |
|||
<button mat-raised-button |
|||
ngxClipboard |
|||
(cbOnSuccess)="onDeviceProfileIdCopied($event)" |
|||
[cbContent]="entity?.id?.id" |
|||
[fxShow]="!isEdit"> |
|||
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon> |
|||
<span translate>device-profile.copyId</span> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<div class="mat-padding" fxLayout="column"> |
|||
<form [formGroup]="entityForm"> |
|||
<fieldset [disabled]="(isLoading$ | async) || !isEdit"> |
|||
<mat-form-field class="mat-block"> |
|||
<mat-label translate>device-profile.name</mat-label> |
|||
<input matInput formControlName="name" required/> |
|||
<mat-error *ngIf="entityForm.get('name').hasError('required')"> |
|||
{{ 'device-profile.name-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<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="entityForm.get('type').hasError('required')"> |
|||
{{ 'device-profile.type-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<tb-device-profile-data |
|||
formControlName="profileData" |
|||
required> |
|||
</tb-device-profile-data> |
|||
<tb-entity-autocomplete |
|||
[entityType]="entityType.RULE_CHAIN" |
|||
formControlName="defaultRuleChainId"> |
|||
</tb-entity-autocomplete> |
|||
<mat-form-field class="mat-block"> |
|||
<mat-label translate>tenant-profile.description</mat-label> |
|||
<textarea matInput formControlName="description" rows="2"></textarea> |
|||
</mat-form-field> |
|||
</fieldset> |
|||
</form> |
|||
</div> |
|||
@ -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, Inject, Input, Optional } from '@angular/core'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { ActionNotificationShow } from '@app/core/notification/notification.actions'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; |
|||
import { EntityComponent } from '../entity/entity.component'; |
|||
import { |
|||
createDeviceProfileConfiguration, |
|||
DeviceProfile, |
|||
DeviceProfileData, |
|||
DeviceProfileType, |
|||
deviceProfileTypeTranslationMap |
|||
} from '@shared/models/device.models'; |
|||
import { EntityType } from '@shared/models/entity-type.models'; |
|||
import { RuleChainId } from '@shared/models/id/rule-chain-id'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-device-profile', |
|||
templateUrl: './device-profile.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class DeviceProfileComponent extends EntityComponent<DeviceProfile> { |
|||
|
|||
@Input() |
|||
standalone = false; |
|||
|
|||
entityType = EntityType; |
|||
|
|||
deviceProfileTypes = Object.keys(DeviceProfileType); |
|||
|
|||
deviceProfileTypeTranslations = deviceProfileTypeTranslationMap; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
protected translate: TranslateService, |
|||
@Optional() @Inject('entity') protected entityValue: DeviceProfile, |
|||
@Optional() @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<DeviceProfile>, |
|||
protected fb: FormBuilder) { |
|||
super(store, fb, entityValue, entitiesTableConfigValue); |
|||
} |
|||
|
|||
hideDelete() { |
|||
if (this.entitiesTableConfig) { |
|||
return !this.entitiesTableConfig.deleteEnabled(this.entity); |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
buildForm(entity: DeviceProfile): FormGroup { |
|||
const form = this.fb.group( |
|||
{ |
|||
name: [entity ? entity.name : '', [Validators.required]], |
|||
type: [entity ? entity.type : '', [Validators.required]], |
|||
profileData: [entity && !this.isAdd ? entity.profileData : {}, []], |
|||
defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], |
|||
description: [entity ? entity.description : '', []], |
|||
} |
|||
); |
|||
form.get('type').valueChanges.subscribe(() => { |
|||
this.deviceProfileTypeChanged(form); |
|||
}); |
|||
this.checkIsNewDeviceProfile(entity, form); |
|||
return form; |
|||
} |
|||
|
|||
private checkIsNewDeviceProfile(entity: DeviceProfile, form: FormGroup) { |
|||
if (entity && !entity.id) { |
|||
form.get('type').patchValue(DeviceProfileType.DEFAULT, {emitEvent: true}); |
|||
} |
|||
} |
|||
|
|||
private deviceProfileTypeChanged(form: FormGroup) { |
|||
const deviceProfileType: DeviceProfileType = form.get('type').value; |
|||
let profileData: DeviceProfileData = form.getRawValue().profileData; |
|||
if (!profileData) { |
|||
profileData = { |
|||
configuration: null |
|||
}; |
|||
} |
|||
profileData.configuration = createDeviceProfileConfiguration(deviceProfileType); |
|||
this.entityForm.patchValue({profileData}); |
|||
} |
|||
|
|||
updateForm(entity: DeviceProfile) { |
|||
this.entityForm.patchValue({name: entity.name}); |
|||
this.entityForm.patchValue({type: entity.type}); |
|||
this.entityForm.patchValue({profileData: entity.profileData}); |
|||
this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}); |
|||
this.entityForm.patchValue({description: entity.description}); |
|||
} |
|||
|
|||
prepareFormValue(formValue: any): any { |
|||
if (formValue.defaultRuleChainId) { |
|||
formValue.defaultRuleChainId = new RuleChainId(formValue.defaultRuleChainId); |
|||
} |
|||
return formValue; |
|||
} |
|||
|
|||
onDeviceProfileIdCopied(event) { |
|||
this.store.dispatch(new ActionNotificationShow( |
|||
{ |
|||
message: this.translate.instant('device-profile.idCopiedMessage'), |
|||
type: 'success', |
|||
duration: 750, |
|||
verticalPosition: 'bottom', |
|||
horizontalPosition: 'right' |
|||
})); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<form [formGroup]="defaultDeviceProfileConfigurationFormGroup" style="padding-bottom: 16px;"> |
|||
<tb-json-object-edit |
|||
[required]="required" |
|||
label="{{ 'device-profile.type-default' | translate }}" |
|||
formControlName="configuration"> |
|||
</tb-json-object-edit> |
|||
</form> |
|||
@ -0,0 +1,97 @@ |
|||
///
|
|||
/// 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, forwardRef, Input, OnInit } from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@app/core/core.state'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { |
|||
DefaultDeviceProfileConfiguration, |
|||
DeviceProfileConfiguration, |
|||
DeviceProfileType |
|||
} from '@shared/models/device.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-default-device-profile-configuration', |
|||
templateUrl: './default-device-profile-configuration.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => DefaultDeviceProfileConfigurationComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class DefaultDeviceProfileConfigurationComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
defaultDeviceProfileConfigurationFormGroup: FormGroup; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.defaultDeviceProfileConfigurationFormGroup = this.fb.group({ |
|||
configuration: [null, Validators.required] |
|||
}); |
|||
this.defaultDeviceProfileConfigurationFormGroup.valueChanges.subscribe(() => { |
|||
this.updateModel(); |
|||
}); |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.defaultDeviceProfileConfigurationFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.defaultDeviceProfileConfigurationFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: DefaultDeviceProfileConfiguration | null): void { |
|||
this.defaultDeviceProfileConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false}); |
|||
} |
|||
|
|||
private updateModel() { |
|||
let configuration: DeviceProfileConfiguration = null; |
|||
if (this.defaultDeviceProfileConfigurationFormGroup.valid) { |
|||
configuration = this.defaultDeviceProfileConfigurationFormGroup.getRawValue().configuration; |
|||
configuration.type = DeviceProfileType.DEFAULT; |
|||
} |
|||
this.propagateChange(configuration); |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
<!-- |
|||
|
|||
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 [formGroup]="deviceProfileConfigurationFormGroup"> |
|||
<div [ngSwitch]="type"> |
|||
<ng-template [ngSwitchCase]="deviceProfileType.DEFAULT"> |
|||
<tb-default-device-profile-configuration |
|||
[required]="required" |
|||
formControlName="configuration"> |
|||
</tb-default-device-profile-configuration> |
|||
</ng-template> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,103 @@ |
|||
///
|
|||
/// 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, forwardRef, Input, OnInit } from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@app/core/core.state'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { DeviceProfileConfiguration, DeviceProfileType } from '@shared/models/device.models'; |
|||
import { deepClone } from '../../../../../core/utils'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-device-profile-configuration', |
|||
templateUrl: './device-profile-configuration.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => DeviceProfileConfigurationComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class DeviceProfileConfigurationComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
deviceProfileType = DeviceProfileType; |
|||
|
|||
deviceProfileConfigurationFormGroup: FormGroup; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
type: DeviceProfileType; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.deviceProfileConfigurationFormGroup = this.fb.group({ |
|||
configuration: [null, Validators.required] |
|||
}); |
|||
this.deviceProfileConfigurationFormGroup.valueChanges.subscribe(() => { |
|||
this.updateModel(); |
|||
}); |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.deviceProfileConfigurationFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.deviceProfileConfigurationFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: DeviceProfileConfiguration | null): void { |
|||
this.type = value?.type; |
|||
const configuration = deepClone(value); |
|||
if (configuration) { |
|||
delete configuration.type; |
|||
} |
|||
this.deviceProfileConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); |
|||
} |
|||
|
|||
private updateModel() { |
|||
let configuration: DeviceProfileConfiguration = null; |
|||
if (this.deviceProfileConfigurationFormGroup.valid) { |
|||
configuration = this.deviceProfileConfigurationFormGroup.getRawValue().configuration; |
|||
configuration.type = this.type; |
|||
} |
|||
this.propagateChange(configuration); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<form [formGroup]="tenantProfileDataFormGroup" style="padding-bottom: 16px;"> |
|||
<tb-json-object-edit |
|||
[required]="required" |
|||
label="{{ 'tenant-profile.data' | translate }}" |
|||
formControlName="tenantProfileData"> |
|||
</tb-json-object-edit> |
|||
</form> |
|||
@ -0,0 +1,93 @@ |
|||
///
|
|||
/// 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, forwardRef, Input, OnInit } from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@app/core/core.state'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { TenantProfileData } from '@shared/models/tenant.model'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-tenant-profile-data', |
|||
templateUrl: './tenant-profile-data.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => TenantProfileDataComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class TenantProfileDataComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
tenantProfileDataFormGroup: FormGroup; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.tenantProfileDataFormGroup = this.fb.group({ |
|||
tenantProfileData: [null, Validators.required] |
|||
}); |
|||
this.tenantProfileDataFormGroup.valueChanges.subscribe(() => { |
|||
this.updateModel(); |
|||
}); |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.tenantProfileDataFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.tenantProfileDataFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: TenantProfileData | null): void { |
|||
this.tenantProfileDataFormGroup.get('tenantProfileData').patchValue(value, {emitEvent: false}); |
|||
} |
|||
|
|||
private updateModel() { |
|||
let tenantProfileData: TenantProfileData = null; |
|||
if (this.tenantProfileDataFormGroup.valid) { |
|||
tenantProfileData = this.tenantProfileDataFormGroup.getRawValue().profileData; |
|||
} |
|||
this.propagateChange(tenantProfileData); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<form (ngSubmit)="save()" style="min-width: 600px;"> |
|||
<mat-toolbar color="primary"> |
|||
<h2>{{ (isAdd ? 'tenant-profile.add' : 'tenant-profile.edit' ) | translate }}</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> |
|||
<tb-tenant-profile |
|||
#tenantProfileComponent |
|||
[standalone]="true" |
|||
[entity]="tenantProfile" |
|||
[isEdit]="true"> |
|||
</tb-tenant-profile> |
|||
</div> |
|||
<div mat-dialog-actions fxLayoutAlign="end center"> |
|||
<button mat-raised-button color="primary" |
|||
type="submit" |
|||
[disabled]="(isLoading$ | async) || tenantProfileComponent.entityForm?.invalid || !tenantProfileComponent.entityForm?.dirty"> |
|||
{{ (isAdd ? 'action.add' : 'action.save') | translate }} |
|||
</button> |
|||
<button mat-button color="primary" |
|||
type="button" |
|||
cdkFocusInitial |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="cancel()"> |
|||
{{ 'action.cancel' | translate }} |
|||
</button> |
|||
</div> |
|||
</form> |
|||
@ -0,0 +1,101 @@ |
|||
///
|
|||
/// 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 { FormControl, FormGroupDirective, NgForm } from '@angular/forms'; |
|||
import { DialogComponent } from '@shared/components/dialog.component'; |
|||
import { Router } from '@angular/router'; |
|||
import { TenantProfile } from '@shared/models/tenant.model'; |
|||
import { TenantProfileComponent } from './tenant-profile.component'; |
|||
import { TenantProfileService } from '@core/http/tenant-profile.service'; |
|||
|
|||
export interface TenantProfileDialogData { |
|||
tenantProfile: TenantProfile; |
|||
isAdd: boolean; |
|||
} |
|||
|
|||
@Component({ |
|||
selector: 'tb-tenant-profile-dialog', |
|||
templateUrl: './tenant-profile-dialog.component.html', |
|||
providers: [{provide: ErrorStateMatcher, useExisting: TenantProfileDialogComponent}], |
|||
styleUrls: [] |
|||
}) |
|||
export class TenantProfileDialogComponent extends |
|||
DialogComponent<TenantProfileDialogComponent, TenantProfile> implements ErrorStateMatcher, AfterViewInit { |
|||
|
|||
isAdd: boolean; |
|||
tenantProfile: TenantProfile; |
|||
|
|||
submitted = false; |
|||
|
|||
@ViewChild('tenantProfileComponent', {static: true}) tenantProfileComponent: TenantProfileComponent; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
protected router: Router, |
|||
@Inject(MAT_DIALOG_DATA) public data: TenantProfileDialogData, |
|||
public dialogRef: MatDialogRef<TenantProfileDialogComponent, TenantProfile>, |
|||
private componentFactoryResolver: ComponentFactoryResolver, |
|||
private injector: Injector, |
|||
@SkipSelf() private errorStateMatcher: ErrorStateMatcher, |
|||
private tenantProfileService: TenantProfileService) { |
|||
super(store, router, dialogRef); |
|||
this.isAdd = this.data.isAdd; |
|||
this.tenantProfile = this.data.tenantProfile; |
|||
} |
|||
|
|||
ngAfterViewInit(): void { |
|||
if (this.isAdd) { |
|||
setTimeout(() => { |
|||
this.tenantProfileComponent.entityForm.markAsDirty(); |
|||
}, 0); |
|||
} |
|||
} |
|||
|
|||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { |
|||
const originalErrorState = this.errorStateMatcher.isErrorState(control, form); |
|||
const customErrorState = !!(control && control.invalid && this.submitted); |
|||
return originalErrorState || customErrorState; |
|||
} |
|||
|
|||
cancel(): void { |
|||
this.dialogRef.close(null); |
|||
} |
|||
|
|||
save(): void { |
|||
this.submitted = true; |
|||
if (this.tenantProfileComponent.entityForm.valid) { |
|||
this.tenantProfile = {...this.tenantProfile, ...this.tenantProfileComponent.entityFormValue()}; |
|||
this.tenantProfileService.saveTenantProfile(this.tenantProfile).subscribe( |
|||
(tenantProfile) => { |
|||
this.dialogRef.close(tenantProfile); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
///
|
|||
/// 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 { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
|
|||
import { EntitiesTableComponent } from '../../components/entity/entities-table.component'; |
|||
import { Authority } from '@shared/models/authority.enum'; |
|||
import { DeviceProfilesTableConfigResolver } from './device-profiles-table-config.resolver'; |
|||
|
|||
const routes: Routes = [ |
|||
{ |
|||
path: 'deviceProfiles', |
|||
data: { |
|||
breadcrumb: { |
|||
label: 'device-profile.device-profiles', |
|||
icon: 'mdi:alpha-d-box' |
|||
} |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: '', |
|||
component: EntitiesTableComponent, |
|||
data: { |
|||
auth: [Authority.TENANT_ADMIN], |
|||
title: 'device-profile.device-profiles' |
|||
}, |
|||
resolve: { |
|||
entitiesTableConfig: DeviceProfilesTableConfigResolver |
|||
} |
|||
} |
|||
] |
|||
} |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
providers: [ |
|||
DeviceProfilesTableConfigResolver |
|||
] |
|||
}) |
|||
export class DeviceProfileRoutingModule { } |
|||
@ -0,0 +1,43 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> |
|||
<tb-attribute-table [defaultAttributeScope]="attributeScopes.SERVER_SCOPE" |
|||
[active]="attributesTab.isActive" |
|||
[entityId]="entity.id" |
|||
[entityName]="entity.name"> |
|||
</tb-attribute-table> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> |
|||
<tb-attribute-table [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" |
|||
disableAttributeScopeSelection |
|||
[active]="telemetryTab.isActive" |
|||
[entityId]="entity.id" |
|||
[entityName]="entity.name"> |
|||
</tb-attribute-table> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'alarm.alarms' | translate }}" #alarmsTab="matTab"> |
|||
<tb-alarm-table [active]="alarmsTab.isActive" [entityId]="entity.id"></tb-alarm-table> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'tenant.events' | translate }}" #eventsTab="matTab"> |
|||
<tb-event-table [defaultEventType]="eventTypes.ERROR" [active]="eventsTab.isActive" [tenantId]="nullUid" |
|||
[entityId]="entity.id"></tb-event-table> |
|||
</mat-tab> |
|||
@ -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.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; |
|||
import { DeviceProfile } from '@shared/models/device.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-device-profile-tabs', |
|||
templateUrl: './device-profile-tabs.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class DeviceProfileTabsComponent extends EntityTabsComponent<DeviceProfile> { |
|||
|
|||
constructor(protected store: Store<AppState>) { |
|||
super(store); |
|||
} |
|||
|
|||
ngOnInit() { |
|||
super.ngOnInit(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
///
|
|||
/// 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 { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { HomeComponentsModule } from '@modules/home/components/home-components.module'; |
|||
import { DeviceProfileTabsComponent } from './device-profile-tabs.component'; |
|||
import { DeviceProfileRoutingModule } from './device-profile-routing.module'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
DeviceProfileTabsComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
HomeComponentsModule, |
|||
DeviceProfileRoutingModule |
|||
] |
|||
}) |
|||
export class DeviceProfileModule { } |
|||
@ -0,0 +1,125 @@ |
|||
///
|
|||
/// 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 { Injectable } from '@angular/core'; |
|||
import { Resolve } from '@angular/router'; |
|||
import { |
|||
checkBoxCell, |
|||
DateEntityTableColumn, |
|||
EntityTableColumn, |
|||
EntityTableConfig |
|||
} from '@home/models/entity/entities-table-config.models'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { DatePipe } from '@angular/common'; |
|||
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; |
|||
import { EntityAction } from '@home/models/entity/entity-component.models'; |
|||
import { DialogService } from '@core/services/dialog.service'; |
|||
import { DeviceProfile, deviceProfileTypeTranslationMap } from '@shared/models/device.models'; |
|||
import { DeviceProfileService } from '@core/http/device-profile.service'; |
|||
import { DeviceProfileComponent } from '../../components/profile/device-profile.component'; |
|||
import { DeviceProfileTabsComponent } from './device-profile-tabs.component'; |
|||
|
|||
@Injectable() |
|||
export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableConfig<DeviceProfile>> { |
|||
|
|||
private readonly config: EntityTableConfig<DeviceProfile> = new EntityTableConfig<DeviceProfile>(); |
|||
|
|||
constructor(private deviceProfileService: DeviceProfileService, |
|||
private translate: TranslateService, |
|||
private datePipe: DatePipe, |
|||
private dialogService: DialogService) { |
|||
|
|||
this.config.entityType = EntityType.DEVICE_PROFILE; |
|||
this.config.entityComponent = DeviceProfileComponent; |
|||
this.config.entityTabsComponent = DeviceProfileTabsComponent; |
|||
this.config.entityTranslations = entityTypeTranslations.get(EntityType.DEVICE_PROFILE); |
|||
this.config.entityResources = entityTypeResources.get(EntityType.DEVICE_PROFILE); |
|||
|
|||
this.config.columns.push( |
|||
new DateEntityTableColumn<DeviceProfile>('createdTime', 'common.created-time', this.datePipe, '150px'), |
|||
new EntityTableColumn<DeviceProfile>('name', 'device-profile.name', '20%'), |
|||
new EntityTableColumn<DeviceProfile>('type', 'device-profile.type', '20%', (deviceProfile) => { |
|||
return this.translate.instant(deviceProfileTypeTranslationMap.get(deviceProfile.type)); |
|||
}), |
|||
new EntityTableColumn<DeviceProfile>('description', 'device-profile.description', '60%'), |
|||
new EntityTableColumn<DeviceProfile>('isDefault', 'device-profile.default', '60px', |
|||
entity => { |
|||
return checkBoxCell(entity.default); |
|||
}) |
|||
); |
|||
|
|||
this.config.cellActionDescriptors.push( |
|||
{ |
|||
name: this.translate.instant('device-profile.set-default'), |
|||
icon: 'flag', |
|||
isEnabled: (deviceProfile) => !deviceProfile.default, |
|||
onAction: ($event, entity) => this.setDefaultDeviceProfile($event, entity) |
|||
} |
|||
); |
|||
|
|||
this.config.deleteEntityTitle = deviceProfile => this.translate.instant('device-profile.delete-device-profile-title', |
|||
{ deviceProfileName: deviceProfile.name }); |
|||
this.config.deleteEntityContent = () => this.translate.instant('device-profile.delete-device-profile-text'); |
|||
this.config.deleteEntitiesTitle = count => this.translate.instant('device-profile.delete-device-profiles-title', {count}); |
|||
this.config.deleteEntitiesContent = () => this.translate.instant('device-profile.delete-device-profiles-text'); |
|||
|
|||
this.config.entitiesFetchFunction = pageLink => this.deviceProfileService.getDeviceProfiles(pageLink); |
|||
this.config.loadEntity = id => this.deviceProfileService.getDeviceProfile(id.id); |
|||
this.config.saveEntity = deviceProfile => this.deviceProfileService.saveDeviceProfile(deviceProfile); |
|||
this.config.deleteEntity = id => this.deviceProfileService.deleteDeviceProfile(id.id); |
|||
this.config.onEntityAction = action => this.onDeviceProfileAction(action); |
|||
this.config.deleteEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default; |
|||
this.config.entitySelectionEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default; |
|||
} |
|||
|
|||
resolve(): EntityTableConfig<DeviceProfile> { |
|||
this.config.tableTitle = this.translate.instant('device-profile.device-profiles'); |
|||
|
|||
return this.config; |
|||
} |
|||
|
|||
setDefaultDeviceProfile($event: Event, deviceProfile: DeviceProfile) { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
this.dialogService.confirm( |
|||
this.translate.instant('device-profile.set-default-device-profile-title', {deviceProfileName: deviceProfile.name}), |
|||
this.translate.instant('device-profile.set-default-device-profile-text'), |
|||
this.translate.instant('action.no'), |
|||
this.translate.instant('action.yes'), |
|||
true |
|||
).subscribe((res) => { |
|||
if (res) { |
|||
this.deviceProfileService.setDefaultDeviceProfile(deviceProfile.id.id).subscribe( |
|||
() => { |
|||
this.config.table.updateData(); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
|
|||
onDeviceProfileAction(action: EntityAction<DeviceProfile>): boolean { |
|||
switch (action.action) { |
|||
case 'setDefault': |
|||
this.setDefaultDeviceProfile(action.event, action.entity); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue