Commit 868234f13df958000e7d72a294f6ab6c613c9b5c

Authored by Igor Kulikov
1 parent fce3bdce

Tenant, device profiles UI

@@ -20,7 +20,7 @@ import { Observable } from 'rxjs'; @@ -20,7 +20,7 @@ import { Observable } from 'rxjs';
20 import { HttpClient } from '@angular/common/http'; 20 import { HttpClient } from '@angular/common/http';
21 import { PageLink } from '@shared/models/page/page-link'; 21 import { PageLink } from '@shared/models/page/page-link';
22 import { PageData } from '@shared/models/page/page-data'; 22 import { PageData } from '@shared/models/page/page-data';
23 -import { Tenant } from '@shared/models/tenant.model'; 23 +import { Tenant, TenantInfo } from '@shared/models/tenant.model';
24 24
25 @Injectable({ 25 @Injectable({
26 providedIn: 'root' 26 providedIn: 'root'
@@ -35,10 +35,18 @@ export class TenantService { @@ -35,10 +35,18 @@ export class TenantService {
35 return this.http.get<PageData<Tenant>>(`/api/tenants${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); 35 return this.http.get<PageData<Tenant>>(`/api/tenants${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config));
36 } 36 }
37 37
  38 + public getTenantInfos(pageLink: PageLink, config?: RequestConfig): Observable<PageData<TenantInfo>> {
  39 + return this.http.get<PageData<TenantInfo>>(`/api/tenantInfos${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config));
  40 + }
  41 +
38 public getTenant(tenantId: string, config?: RequestConfig): Observable<Tenant> { 42 public getTenant(tenantId: string, config?: RequestConfig): Observable<Tenant> {
39 return this.http.get<Tenant>(`/api/tenant/${tenantId}`, defaultHttpOptionsFromConfig(config)); 43 return this.http.get<Tenant>(`/api/tenant/${tenantId}`, defaultHttpOptionsFromConfig(config));
40 } 44 }
41 45
  46 + public getTenantInfo(tenantId: string, config?: RequestConfig): Observable<TenantInfo> {
  47 + return this.http.get<TenantInfo>(`/api/tenant/info/${tenantId}`, defaultHttpOptionsFromConfig(config));
  48 + }
  49 +
42 public saveTenant(tenant: Tenant, config?: RequestConfig): Observable<Tenant> { 50 public saveTenant(tenant: Tenant, config?: RequestConfig): Observable<Tenant> {
43 return this.http.post<Tenant>('/api/tenant', tenant, defaultHttpOptionsFromConfig(config)); 51 return this.http.post<Tenant>('/api/tenant', tenant, defaultHttpOptionsFromConfig(config));
44 } 52 }
@@ -70,8 +70,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -70,8 +70,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
70 return this.fb.group( 70 return this.fb.group(
71 { 71 {
72 name: [entity ? entity.name : '', [Validators.required]], 72 name: [entity ? entity.name : '', [Validators.required]],
  73 + deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]],
73 type: [entity ? entity.type : null, [Validators.required]], 74 type: [entity ? entity.type : null, [Validators.required]],
74 label: [entity ? entity.label : ''], 75 label: [entity ? entity.label : ''],
  76 + deviceData: [entity ? entity.deviceData : null, [Validators.required]],
75 additionalInfo: this.fb.group( 77 additionalInfo: this.fb.group(
76 { 78 {
77 gateway: [entity && entity.additionalInfo ? entity.additionalInfo.gateway : false], 79 gateway: [entity && entity.additionalInfo ? entity.additionalInfo.gateway : false],
@@ -84,8 +86,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { @@ -84,8 +86,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
84 86
85 updateForm(entity: DeviceInfo) { 87 updateForm(entity: DeviceInfo) {
86 this.entityForm.patchValue({name: entity.name}); 88 this.entityForm.patchValue({name: entity.name});
  89 + this.entityForm.patchValue({deviceProfileId: entity.deviceProfileId});
87 this.entityForm.patchValue({type: entity.type}); 90 this.entityForm.patchValue({type: entity.type});
88 this.entityForm.patchValue({label: entity.label}); 91 this.entityForm.patchValue({label: entity.label});
  92 + this.entityForm.patchValue({deviceData: entity.deviceData});
89 this.entityForm.patchValue({additionalInfo: 93 this.entityForm.patchValue({additionalInfo:
90 {gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false}}); 94 {gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false}});
91 this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); 95 this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
@@ -150,13 +150,14 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev @@ -150,13 +150,14 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
150 configureColumns(deviceScope: string): Array<EntityTableColumn<DeviceInfo>> { 150 configureColumns(deviceScope: string): Array<EntityTableColumn<DeviceInfo>> {
151 const columns: Array<EntityTableColumn<DeviceInfo>> = [ 151 const columns: Array<EntityTableColumn<DeviceInfo>> = [
152 new DateEntityTableColumn<DeviceInfo>('createdTime', 'common.created-time', this.datePipe, '150px'), 152 new DateEntityTableColumn<DeviceInfo>('createdTime', 'common.created-time', this.datePipe, '150px'),
153 - new EntityTableColumn<DeviceInfo>('name', 'device.name', '25%'),  
154 - new EntityTableColumn<DeviceInfo>('type', 'device.device-type', '25%'),  
155 - new EntityTableColumn<DeviceInfo>('label', 'device.label', '25%') 153 + new EntityTableColumn<DeviceInfo>('name', 'device.name', '20%'),
  154 + new EntityTableColumn<DeviceInfo>('deviceProfileName', 'device-profile.device-profile', '20%'),
  155 + new EntityTableColumn<DeviceInfo>('type', 'device.device-type', '20%'),
  156 + new EntityTableColumn<DeviceInfo>('label', 'device.label', '20%')
156 ]; 157 ];
157 if (deviceScope === 'tenant') { 158 if (deviceScope === 'tenant') {
158 columns.push( 159 columns.push(
159 - new EntityTableColumn<DeviceInfo>('customerTitle', 'customer.customer', '25%'), 160 + new EntityTableColumn<DeviceInfo>('customerTitle', 'customer.customer', '20%'),
160 new EntityTableColumn<DeviceInfo>('customerIsPublic', 'device.public', '60px', 161 new EntityTableColumn<DeviceInfo>('customerIsPublic', 'device.public', '60px',
161 entity => { 162 entity => {
162 return checkBoxCell(entity.customerIsPublic); 163 return checkBoxCell(entity.customerIsPublic);
@@ -18,14 +18,14 @@ import { Component } from '@angular/core'; @@ -18,14 +18,14 @@ import { Component } from '@angular/core';
18 import { Store } from '@ngrx/store'; 18 import { Store } from '@ngrx/store';
19 import { AppState } from '@core/core.state'; 19 import { AppState } from '@core/core.state';
20 import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; 20 import { EntityTabsComponent } from '../../components/entity/entity-tabs.component';
21 -import { Tenant } from '@shared/models/tenant.model'; 21 +import { TenantInfo } from '@shared/models/tenant.model';
22 22
23 @Component({ 23 @Component({
24 selector: 'tb-tenant-tabs', 24 selector: 'tb-tenant-tabs',
25 templateUrl: './tenant-tabs.component.html', 25 templateUrl: './tenant-tabs.component.html',
26 styleUrls: [] 26 styleUrls: []
27 }) 27 })
28 -export class TenantTabsComponent extends EntityTabsComponent<Tenant> { 28 +export class TenantTabsComponent extends EntityTabsComponent<TenantInfo> {
29 29
30 constructor(protected store: Store<AppState>) { 30 constructor(protected store: Store<AppState>) {
31 super(store); 31 super(store);
@@ -18,7 +18,7 @@ import { Component, Inject } from '@angular/core'; @@ -18,7 +18,7 @@ import { Component, Inject } from '@angular/core';
18 import { Store } from '@ngrx/store'; 18 import { Store } from '@ngrx/store';
19 import { AppState } from '@core/core.state'; 19 import { AppState } from '@core/core.state';
20 import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 20 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
21 -import { Tenant } from '@app/shared/models/tenant.model'; 21 +import { Tenant, TenantInfo } from '@app/shared/models/tenant.model';
22 import { ActionNotificationShow } from '@app/core/notification/notification.actions'; 22 import { ActionNotificationShow } from '@app/core/notification/notification.actions';
23 import { TranslateService } from '@ngx-translate/core'; 23 import { TranslateService } from '@ngx-translate/core';
24 import { ContactBasedComponent } from '../../components/entity/contact-based.component'; 24 import { ContactBasedComponent } from '../../components/entity/contact-based.component';
@@ -29,12 +29,12 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod @@ -29,12 +29,12 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod
29 templateUrl: './tenant.component.html', 29 templateUrl: './tenant.component.html',
30 styleUrls: ['./tenant.component.scss'] 30 styleUrls: ['./tenant.component.scss']
31 }) 31 })
32 -export class TenantComponent extends ContactBasedComponent<Tenant> { 32 +export class TenantComponent extends ContactBasedComponent<TenantInfo> {
33 33
34 constructor(protected store: Store<AppState>, 34 constructor(protected store: Store<AppState>,
35 protected translate: TranslateService, 35 protected translate: TranslateService,
36 - @Inject('entity') protected entityValue: Tenant,  
37 - @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<Tenant>, 36 + @Inject('entity') protected entityValue: TenantInfo,
  37 + @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<TenantInfo>,
38 protected fb: FormBuilder) { 38 protected fb: FormBuilder) {
39 super(store, fb, entityValue, entitiesTableConfigValue); 39 super(store, fb, entityValue, entitiesTableConfigValue);
40 } 40 }
@@ -47,12 +47,13 @@ export class TenantComponent extends ContactBasedComponent<Tenant> { @@ -47,12 +47,13 @@ export class TenantComponent extends ContactBasedComponent<Tenant> {
47 } 47 }
48 } 48 }
49 49
50 - buildEntityForm(entity: Tenant): FormGroup { 50 + buildEntityForm(entity: TenantInfo): FormGroup {
51 return this.fb.group( 51 return this.fb.group(
52 { 52 {
53 title: [entity ? entity.title : '', [Validators.required]], 53 title: [entity ? entity.title : '', [Validators.required]],
54 - isolatedTbCore: [entity ? entity.isolatedTbCore : false, []],  
55 - isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], 54 + tenantProfileId: [entity ? entity.tenantProfileId : null, [Validators.required]],
  55 + // isolatedTbCore: [entity ? entity.isolatedTbCore : false, []],
  56 + // isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []],
56 additionalInfo: this.fb.group( 57 additionalInfo: this.fb.group(
57 { 58 {
58 description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''] 59 description: [entity && entity.additionalInfo ? entity.additionalInfo.description : '']
@@ -64,8 +65,9 @@ export class TenantComponent extends ContactBasedComponent<Tenant> { @@ -64,8 +65,9 @@ export class TenantComponent extends ContactBasedComponent<Tenant> {
64 65
65 updateEntityForm(entity: Tenant) { 66 updateEntityForm(entity: Tenant) {
66 this.entityForm.patchValue({title: entity.title}); 67 this.entityForm.patchValue({title: entity.title});
67 - this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore});  
68 - this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}); 68 + this.entityForm.patchValue({tenantProfileId: entity.tenantProfileId});
  69 + // this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore});
  70 + // this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine});
69 this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); 71 this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
70 } 72 }
71 73
@@ -73,10 +75,10 @@ export class TenantComponent extends ContactBasedComponent<Tenant> { @@ -73,10 +75,10 @@ export class TenantComponent extends ContactBasedComponent<Tenant> {
73 if (this.entityForm) { 75 if (this.entityForm) {
74 if (this.isEditValue) { 76 if (this.isEditValue) {
75 this.entityForm.enable({emitEvent: false}); 77 this.entityForm.enable({emitEvent: false});
76 - if (!this.isAdd) { 78 + /* if (!this.isAdd) {
77 this.entityForm.get('isolatedTbCore').disable({emitEvent: false}); 79 this.entityForm.get('isolatedTbCore').disable({emitEvent: false});
78 this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false}); 80 this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false});
79 - } 81 + } */
80 } else { 82 } else {
81 this.entityForm.disable({emitEvent: false}); 83 this.entityForm.disable({emitEvent: false});
82 } 84 }
@@ -18,7 +18,7 @@ import { Injectable } from '@angular/core'; @@ -18,7 +18,7 @@ import { Injectable } from '@angular/core';
18 18
19 import { Resolve, Router } from '@angular/router'; 19 import { Resolve, Router } from '@angular/router';
20 20
21 -import { Tenant } from '@shared/models/tenant.model'; 21 +import { TenantInfo } from '@shared/models/tenant.model';
22 import { 22 import {
23 DateEntityTableColumn, 23 DateEntityTableColumn,
24 EntityTableColumn, 24 EntityTableColumn,
@@ -31,11 +31,12 @@ import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared @@ -31,11 +31,12 @@ import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared
31 import { TenantComponent } from '@modules/home/pages/tenant/tenant.component'; 31 import { TenantComponent } from '@modules/home/pages/tenant/tenant.component';
32 import { EntityAction } from '@home/models/entity/entity-component.models'; 32 import { EntityAction } from '@home/models/entity/entity-component.models';
33 import { TenantTabsComponent } from '@home/pages/tenant/tenant-tabs.component'; 33 import { TenantTabsComponent } from '@home/pages/tenant/tenant-tabs.component';
  34 +import { mergeMap } from 'rxjs/operators';
34 35
35 @Injectable() 36 @Injectable()
36 -export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Tenant>> { 37 +export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<TenantInfo>> {
37 38
38 - private readonly config: EntityTableConfig<Tenant> = new EntityTableConfig<Tenant>(); 39 + private readonly config: EntityTableConfig<TenantInfo> = new EntityTableConfig<TenantInfo>();
39 40
40 constructor(private tenantService: TenantService, 41 constructor(private tenantService: TenantService,
41 private translate: TranslateService, 42 private translate: TranslateService,
@@ -49,11 +50,12 @@ export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Ten @@ -49,11 +50,12 @@ export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Ten
49 this.config.entityResources = entityTypeResources.get(EntityType.TENANT); 50 this.config.entityResources = entityTypeResources.get(EntityType.TENANT);
50 51
51 this.config.columns.push( 52 this.config.columns.push(
52 - new DateEntityTableColumn<Tenant>('createdTime', 'common.created-time', this.datePipe, '150px'),  
53 - new EntityTableColumn<Tenant>('title', 'tenant.title', '25%'),  
54 - new EntityTableColumn<Tenant>('email', 'contact.email', '25%'),  
55 - new EntityTableColumn<Tenant>('country', 'contact.country', '25%'),  
56 - new EntityTableColumn<Tenant>('city', 'contact.city', '25%') 53 + new DateEntityTableColumn<TenantInfo>('createdTime', 'common.created-time', this.datePipe, '150px'),
  54 + new EntityTableColumn<TenantInfo>('title', 'tenant-profile.tenant-profile', '20%'),
  55 + new EntityTableColumn<TenantInfo>('tenantProfileName', 'tenant.title', '20%'),
  56 + new EntityTableColumn<TenantInfo>('email', 'contact.email', '20%'),
  57 + new EntityTableColumn<TenantInfo>('country', 'contact.country', '20%'),
  58 + new EntityTableColumn<TenantInfo>('city', 'contact.city', '20%')
57 ); 59 );
58 60
59 this.config.cellActionDescriptors.push( 61 this.config.cellActionDescriptors.push(
@@ -70,27 +72,29 @@ export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Ten @@ -70,27 +72,29 @@ export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Ten
70 this.config.deleteEntitiesTitle = count => this.translate.instant('tenant.delete-tenants-title', {count}); 72 this.config.deleteEntitiesTitle = count => this.translate.instant('tenant.delete-tenants-title', {count});
71 this.config.deleteEntitiesContent = () => this.translate.instant('tenant.delete-tenants-text'); 73 this.config.deleteEntitiesContent = () => this.translate.instant('tenant.delete-tenants-text');
72 74
73 - this.config.entitiesFetchFunction = pageLink => this.tenantService.getTenants(pageLink);  
74 - this.config.loadEntity = id => this.tenantService.getTenant(id.id);  
75 - this.config.saveEntity = tenant => this.tenantService.saveTenant(tenant); 75 + this.config.entitiesFetchFunction = pageLink => this.tenantService.getTenantInfos(pageLink);
  76 + this.config.loadEntity = id => this.tenantService.getTenantInfo(id.id);
  77 + this.config.saveEntity = tenant => this.tenantService.saveTenant(tenant).pipe(
  78 + mergeMap((savedTenant) => this.tenantService.getTenantInfo(savedTenant.id.id))
  79 + );
76 this.config.deleteEntity = id => this.tenantService.deleteTenant(id.id); 80 this.config.deleteEntity = id => this.tenantService.deleteTenant(id.id);
77 this.config.onEntityAction = action => this.onTenantAction(action); 81 this.config.onEntityAction = action => this.onTenantAction(action);
78 } 82 }
79 83
80 - resolve(): EntityTableConfig<Tenant> { 84 + resolve(): EntityTableConfig<TenantInfo> {
81 this.config.tableTitle = this.translate.instant('tenant.tenants'); 85 this.config.tableTitle = this.translate.instant('tenant.tenants');
82 86
83 return this.config; 87 return this.config;
84 } 88 }
85 89
86 - manageTenantAdmins($event: Event, tenant: Tenant) { 90 + manageTenantAdmins($event: Event, tenant: TenantInfo) {
87 if ($event) { 91 if ($event) {
88 $event.stopPropagation(); 92 $event.stopPropagation();
89 } 93 }
90 this.router.navigateByUrl(`tenants/${tenant.id.id}/users`); 94 this.router.navigateByUrl(`tenants/${tenant.id.id}/users`);
91 } 95 }
92 96
93 - onTenantAction(action: EntityAction<Tenant>): boolean { 97 + onTenantAction(action: EntityAction<TenantInfo>): boolean {
94 switch (action.action) { 98 switch (action.action) {
95 case 'manageTenantAdmins': 99 case 'manageTenantAdmins':
96 this.manageTenantAdmins(action.event, action.entity); 100 this.manageTenantAdmins(action.event, action.entity);
@@ -107,9 +107,11 @@ export const HelpLinks = { @@ -107,9 +107,11 @@ export const HelpLinks = {
107 ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node', 107 ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node',
108 ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node', 108 ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node',
109 tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', 109 tenants: helpBaseUrl + '/docs/user-guide/ui/tenants',
  110 + tenantProfiles: helpBaseUrl + '/docs/user-guide/ui/tenant-profiles',
110 customers: helpBaseUrl + '/docs/user-guide/ui/customers', 111 customers: helpBaseUrl + '/docs/user-guide/ui/customers',
111 users: helpBaseUrl + '/docs/user-guide/ui/users', 112 users: helpBaseUrl + '/docs/user-guide/ui/users',
112 devices: helpBaseUrl + '/docs/user-guide/ui/devices', 113 devices: helpBaseUrl + '/docs/user-guide/ui/devices',
  114 + deviceProfiles: helpBaseUrl + '/docs/user-guide/ui/device-profiles',
113 assets: helpBaseUrl + '/docs/user-guide/ui/assets', 115 assets: helpBaseUrl + '/docs/user-guide/ui/assets',
114 entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views', 116 entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views',
115 entitiesImport: helpBaseUrl + '/docs/user-guide/bulk-provisioning', 117 entitiesImport: helpBaseUrl + '/docs/user-guide/bulk-provisioning',
@@ -20,6 +20,62 @@ import { TenantId } from '@shared/models/id/tenant-id'; @@ -20,6 +20,62 @@ import { TenantId } from '@shared/models/id/tenant-id';
20 import { CustomerId } from '@shared/models/id/customer-id'; 20 import { CustomerId } from '@shared/models/id/customer-id';
21 import { DeviceCredentialsId } from '@shared/models/id/device-credentials-id'; 21 import { DeviceCredentialsId } from '@shared/models/id/device-credentials-id';
22 import { EntitySearchQuery } from '@shared/models/relation.models'; 22 import { EntitySearchQuery } from '@shared/models/relation.models';
  23 +import { DeviceProfileId } from '@shared/models/id/device-profile-id';
  24 +import { RuleChainId } from '@shared/models/id/rule-chain-id';
  25 +import { EntityInfoData } from '@shared/models/entity.models';
  26 +
  27 +export enum DeviceProfileType {
  28 + DEFAULT = 'DEFAULT',
  29 + LWM2M = 'LWM2M'
  30 +}
  31 +
  32 +export interface DefaultDeviceProfileConfiguration {
  33 + [key: string]: any;
  34 +}
  35 +export interface Lwm2mDeviceProfileConfiguration {
  36 + [key: string]: any;
  37 +}
  38 +
  39 +export type DeviceProfileConfigurations = DefaultDeviceProfileConfiguration & Lwm2mDeviceProfileConfiguration;
  40 +
  41 +export interface DeviceProfileConfiguration extends DeviceProfileConfigurations {
  42 + type: DeviceProfileType;
  43 +}
  44 +
  45 +export interface DeviceProfileData {
  46 + configuration: DeviceProfileConfiguration;
  47 +}
  48 +
  49 +export interface DeviceProfile extends BaseData<DeviceProfileId> {
  50 + tenantId?: TenantId;
  51 + name: string;
  52 + description?: string;
  53 + isDefault: boolean;
  54 + type: DeviceProfileType;
  55 + defaultRuleChainId?: RuleChainId;
  56 + profileData: DeviceProfileData;
  57 +}
  58 +
  59 +export interface DeviceProfileInfo extends EntityInfoData {
  60 + type: DeviceProfileType;
  61 +}
  62 +
  63 +export interface DefaultDeviceConfiguration {
  64 + [key: string]: any;
  65 +}
  66 +export interface Lwm2mDeviceConfiguration {
  67 + [key: string]: any;
  68 +}
  69 +
  70 +export type DeviceConfigurations = DefaultDeviceConfiguration & Lwm2mDeviceConfiguration;
  71 +
  72 +export interface DeviceConfiguration extends DeviceConfigurations {
  73 + type: DeviceProfileType;
  74 +}
  75 +
  76 +export interface DeviceData {
  77 + configuration: DeviceConfiguration;
  78 +}
23 79
24 export interface Device extends BaseData<DeviceId> { 80 export interface Device extends BaseData<DeviceId> {
25 tenantId?: TenantId; 81 tenantId?: TenantId;
@@ -27,12 +83,15 @@ export interface Device extends BaseData<DeviceId> { @@ -27,12 +83,15 @@ export interface Device extends BaseData<DeviceId> {
27 name: string; 83 name: string;
28 type: string; 84 type: string;
29 label: string; 85 label: string;
  86 + deviceProfileId: DeviceProfileId;
  87 + deviceData: DeviceData;
30 additionalInfo?: any; 88 additionalInfo?: any;
31 } 89 }
32 90
33 export interface DeviceInfo extends Device { 91 export interface DeviceInfo extends Device {
34 customerTitle: string; 92 customerTitle: string;
35 customerIsPublic: boolean; 93 customerIsPublic: boolean;
  94 + deviceProfileName: string;
36 } 95 }
37 96
38 export enum DeviceCredentialsType { 97 export enum DeviceCredentialsType {
@@ -69,6 +128,6 @@ export enum ClaimResponse { @@ -69,6 +128,6 @@ export enum ClaimResponse {
69 } 128 }
70 129
71 export interface ClaimResult { 130 export interface ClaimResult {
72 - device: Device,  
73 - response: ClaimResponse 131 + device: Device;
  132 + response: ClaimResponse;
74 } 133 }
@@ -35,11 +35,13 @@ import { BaseData, HasId } from '@shared/models/base-data'; @@ -35,11 +35,13 @@ import { BaseData, HasId } from '@shared/models/base-data';
35 35
36 export enum EntityType { 36 export enum EntityType {
37 TENANT = 'TENANT', 37 TENANT = 'TENANT',
  38 + TENANT_PROFILE = 'TENANT_PROFILE',
38 CUSTOMER = 'CUSTOMER', 39 CUSTOMER = 'CUSTOMER',
39 USER = 'USER', 40 USER = 'USER',
40 DASHBOARD = 'DASHBOARD', 41 DASHBOARD = 'DASHBOARD',
41 ASSET = 'ASSET', 42 ASSET = 'ASSET',
42 DEVICE = 'DEVICE', 43 DEVICE = 'DEVICE',
  44 + DEVICE_PROFILE = 'DEVICE_PROFILE',
43 ALARM = 'ALARM', 45 ALARM = 'ALARM',
44 RULE_CHAIN = 'RULE_CHAIN', 46 RULE_CHAIN = 'RULE_CHAIN',
45 RULE_NODE = 'RULE_NODE', 47 RULE_NODE = 'RULE_NODE',
@@ -89,6 +91,20 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti @@ -89,6 +91,20 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
89 } 91 }
90 ], 92 ],
91 [ 93 [
  94 + EntityType.TENANT_PROFILE,
  95 + {
  96 + type: 'entity.type-tenant-profile',
  97 + typePlural: 'entity.type-tenant-profiles',
  98 + list: 'entity.list-of-tenant-profiles',
  99 + nameStartsWith: 'entity.tenant-profile-name-starts-with',
  100 + details: 'tenant-profile.tenant-profile-details',
  101 + add: 'tenant-profile.add',
  102 + noEntities: 'tenant-profile.no-tenant-profiles-text',
  103 + search: 'tenant-profile.search',
  104 + selectedEntities: 'tenant-profile.selected-tenant-profiles'
  105 + }
  106 + ],
  107 + [
92 EntityType.CUSTOMER, 108 EntityType.CUSTOMER,
93 { 109 {
94 type: 'entity.type-customer', 110 type: 'entity.type-customer',
@@ -131,6 +147,20 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti @@ -131,6 +147,20 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
131 } 147 }
132 ], 148 ],
133 [ 149 [
  150 + EntityType.DEVICE_PROFILE,
  151 + {
  152 + type: 'entity.type-device-profile',
  153 + typePlural: 'entity.type-device-profiles',
  154 + list: 'entity.list-of-device-profiles',
  155 + nameStartsWith: 'entity.device-profile-name-starts-with',
  156 + details: 'device-profile.device-profile-details',
  157 + add: 'device-profile.add',
  158 + noEntities: 'device-profile.no-device-profiles-text',
  159 + search: 'device-profile.search',
  160 + selectedEntities: 'device-profile.selected-device-profiles'
  161 + }
  162 + ],
  163 + [
134 EntityType.ASSET, 164 EntityType.ASSET,
135 { 165 {
136 type: 'entity.type-asset', 166 type: 'entity.type-asset',
@@ -258,6 +288,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa @@ -258,6 +288,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa
258 } 288 }
259 ], 289 ],
260 [ 290 [
  291 + EntityType.TENANT_PROFILE,
  292 + {
  293 + helpLinkId: 'tenantProfiles'
  294 + }
  295 + ],
  296 + [
261 EntityType.CUSTOMER, 297 EntityType.CUSTOMER,
262 { 298 {
263 helpLinkId: 'customers' 299 helpLinkId: 'customers'
@@ -276,6 +312,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa @@ -276,6 +312,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa
276 } 312 }
277 ], 313 ],
278 [ 314 [
  315 + EntityType.DEVICE_PROFILE,
  316 + {
  317 + helpLinkId: 'deviceProfiles'
  318 + }
  319 + ],
  320 + [
279 EntityType.ASSET, 321 EntityType.ASSET,
280 { 322 {
281 helpLinkId: 'assets' 323 helpLinkId: 'assets'
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 16
17 import { EntityType } from '@shared/models/entity-type.models'; 17 import { EntityType } from '@shared/models/entity-type.models';
18 import { AttributeData } from './telemetry/telemetry.models'; 18 import { AttributeData } from './telemetry/telemetry.models';
  19 +import { EntityId } from '@shared/models/id/entity-id';
19 20
20 export interface EntityInfo { 21 export interface EntityInfo {
21 name?: string; 22 name?: string;
@@ -25,6 +26,11 @@ export interface EntityInfo { @@ -25,6 +26,11 @@ export interface EntityInfo {
25 entityDescription?: string; 26 entityDescription?: string;
26 } 27 }
27 28
  29 +export interface EntityInfoData {
  30 + id: EntityId;
  31 + name: string;
  32 +}
  33 +
28 export interface ImportEntityData { 34 export interface ImportEntityData {
29 name: string; 35 name: string;
30 type: string; 36 type: string;
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { EntityId } from './entity-id';
  18 +import { EntityType } from '@shared/models/entity-type.models';
  19 +
  20 +export class DeviceProfileId implements EntityId {
  21 + entityType = EntityType.DEVICE_PROFILE;
  22 + id: string;
  23 + constructor(id: string) {
  24 + this.id = id;
  25 + }
  26 +}
@@ -21,6 +21,7 @@ export * from './customer-id'; @@ -21,6 +21,7 @@ export * from './customer-id';
21 export * from './dashboard-id'; 21 export * from './dashboard-id';
22 export * from './device-credentials-id'; 22 export * from './device-credentials-id';
23 export * from './device-id'; 23 export * from './device-id';
  24 +export * from './device-profile-id';
24 export * from './entity-id'; 25 export * from './entity-id';
25 export * from './entity-view-id'; 26 export * from './entity-view-id';
26 export * from './event-id'; 27 export * from './event-id';
@@ -28,6 +29,7 @@ export * from './has-uuid'; @@ -28,6 +29,7 @@ export * from './has-uuid';
28 export * from './rule-chain-id'; 29 export * from './rule-chain-id';
29 export * from './rule-node-id'; 30 export * from './rule-node-id';
30 export * from './tenant-id'; 31 export * from './tenant-id';
  32 +export * from './tenant-profile-id';
31 export * from './user-id'; 33 export * from './user-id';
32 export * from './widget-type-id'; 34 export * from './widget-type-id';
33 export * from './widgets-bundle-id'; 35 export * from './widgets-bundle-id';
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { EntityId } from './entity-id';
  18 +import { EntityType } from '@shared/models/entity-type.models';
  19 +
  20 +export class TenantProfileId implements EntityId {
  21 + entityType = EntityType.TENANT_PROFILE;
  22 + id: string;
  23 + constructor(id: string) {
  24 + this.id = id;
  25 + }
  26 +}
@@ -50,7 +50,7 @@ export function entityKeyTypeToDataKeyType(entityKeyType: EntityKeyType): DataKe @@ -50,7 +50,7 @@ export function entityKeyTypeToDataKeyType(entityKeyType: EntityKeyType): DataKe
50 case EntityKeyType.CLIENT_ATTRIBUTE: 50 case EntityKeyType.CLIENT_ATTRIBUTE:
51 case EntityKeyType.SHARED_ATTRIBUTE: 51 case EntityKeyType.SHARED_ATTRIBUTE:
52 case EntityKeyType.SERVER_ATTRIBUTE: 52 case EntityKeyType.SERVER_ATTRIBUTE:
53 - return DataKeyType.attribute 53 + return DataKeyType.attribute;
54 case EntityKeyType.TIME_SERIES: 54 case EntityKeyType.TIME_SERIES:
55 return DataKeyType.timeseries; 55 return DataKeyType.timeseries;
56 case EntityKeyType.ENTITY_FIELD: 56 case EntityKeyType.ENTITY_FIELD:
@@ -81,11 +81,10 @@ export interface EntityKey { @@ -81,11 +81,10 @@ export interface EntityKey {
81 } 81 }
82 82
83 export function dataKeyToEntityKey(dataKey: DataKey): EntityKey { 83 export function dataKeyToEntityKey(dataKey: DataKey): EntityKey {
84 - const entityKey: EntityKey = { 84 + return {
85 key: dataKey.name, 85 key: dataKey.name,
86 type: dataKeyTypeToEntityKeyType(dataKey.type) 86 type: dataKeyTypeToEntityKeyType(dataKey.type)
87 }; 87 };
88 - return entityKey;  
89 } 88 }
90 89
91 export enum EntityKeyValueType { 90 export enum EntityKeyValueType {
@@ -287,26 +286,26 @@ export interface FilterPredicateValue<T> { @@ -287,26 +286,26 @@ export interface FilterPredicateValue<T> {
287 } 286 }
288 287
289 export interface StringFilterPredicate { 288 export interface StringFilterPredicate {
290 - type: FilterPredicateType.STRING, 289 + type: FilterPredicateType.STRING;
291 operation: StringOperation; 290 operation: StringOperation;
292 value: FilterPredicateValue<string>; 291 value: FilterPredicateValue<string>;
293 ignoreCase: boolean; 292 ignoreCase: boolean;
294 } 293 }
295 294
296 export interface NumericFilterPredicate { 295 export interface NumericFilterPredicate {
297 - type: FilterPredicateType.NUMERIC, 296 + type: FilterPredicateType.NUMERIC;
298 operation: NumericOperation; 297 operation: NumericOperation;
299 value: FilterPredicateValue<number>; 298 value: FilterPredicateValue<number>;
300 } 299 }
301 300
302 export interface BooleanFilterPredicate { 301 export interface BooleanFilterPredicate {
303 - type: FilterPredicateType.BOOLEAN, 302 + type: FilterPredicateType.BOOLEAN;
304 operation: BooleanOperation; 303 operation: BooleanOperation;
305 value: FilterPredicateValue<boolean>; 304 value: FilterPredicateValue<boolean>;
306 } 305 }
307 306
308 export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> { 307 export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> {
309 - type: FilterPredicateType.COMPLEX, 308 + type: FilterPredicateType.COMPLEX;
310 operation: ComplexOperation; 309 operation: ComplexOperation;
311 predicates: Array<T>; 310 predicates: Array<T>;
312 } 311 }
@@ -481,7 +480,7 @@ export interface Filter extends FilterInfo { @@ -481,7 +480,7 @@ export interface Filter extends FilterInfo {
481 } 480 }
482 481
483 export interface Filters { 482 export interface Filters {
484 - [id: string]: Filter 483 + [id: string]: Filter;
485 } 484 }
486 485
487 export interface EntityFilter extends EntityFilters { 486 export interface EntityFilter extends EntityFilters {
@@ -535,7 +534,7 @@ export function createDefaultEntityDataPageLink(pageSize: number): EntityDataPag @@ -535,7 +534,7 @@ export function createDefaultEntityDataPageLink(pageSize: number): EntityDataPag
535 }, 534 },
536 direction: Direction.DESC 535 direction: Direction.DESC
537 } 536 }
538 - } 537 + };
539 } 538 }
540 539
541 export const singleEntityDataPageLink: EntityDataPageLink = createDefaultEntityDataPageLink(1); 540 export const singleEntityDataPageLink: EntityDataPageLink = createDefaultEntityDataPageLink(1);
@@ -16,11 +16,29 @@ @@ -16,11 +16,29 @@
16 16
17 import { ContactBased } from '@shared/models/contact-based.model'; 17 import { ContactBased } from '@shared/models/contact-based.model';
18 import { TenantId } from './id/tenant-id'; 18 import { TenantId } from './id/tenant-id';
  19 +import { TenantProfileId } from '@shared/models/id/tenant-profile-id';
  20 +import { BaseData } from '@shared/models/base-data';
  21 +
  22 +export interface TenantProfileData {
  23 + [key: string]: string;
  24 +}
  25 +
  26 +export interface TenantProfile extends BaseData<TenantProfileId> {
  27 + name: string;
  28 + description: string;
  29 + isDefault: boolean;
  30 + isolatedTbCore: boolean;
  31 + isolatedTbRuleEngine: boolean;
  32 + profileData: TenantProfileData;
  33 +}
19 34
20 export interface Tenant extends ContactBased<TenantId> { 35 export interface Tenant extends ContactBased<TenantId> {
21 title: string; 36 title: string;
22 region: string; 37 region: string;
23 - isolatedTbCore: boolean;  
24 - isolatedTbRuleEngine: boolean; 38 + tenantProfileId: TenantProfileId;
25 additionalInfo?: any; 39 additionalInfo?: any;
26 } 40 }
  41 +
  42 +export interface TenantInfo extends Tenant {
  43 + tenantProfileName: string;
  44 +}
@@ -750,6 +750,15 @@ @@ -750,6 +750,15 @@
750 "search": "Search devices", 750 "search": "Search devices",
751 "selected-devices": "{ count, plural, 1 {1 device} other {# devices} } selected" 751 "selected-devices": "{ count, plural, 1 {1 device} other {# devices} } selected"
752 }, 752 },
  753 + "device-profile": {
  754 + "device-profile": "Device profile",
  755 + "device-profiles": "Device profiles",
  756 + "add": "Add device profile",
  757 + "device-profile-details": "Device profile details",
  758 + "no-device-profiles-text": "No device profiles found",
  759 + "search": "Search device profiles",
  760 + "selected-device-profiles": "{ count, plural, 1 {1 device profile} other {# device profiles} } selected"
  761 + },
753 "dialog": { 762 "dialog": {
754 "close": "Close dialog" 763 "close": "Close dialog"
755 }, 764 },
@@ -806,6 +815,10 @@ @@ -806,6 +815,10 @@
806 "type-devices": "Devices", 815 "type-devices": "Devices",
807 "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", 816 "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }",
808 "device-name-starts-with": "Devices whose names start with '{{prefix}}'", 817 "device-name-starts-with": "Devices whose names start with '{{prefix}}'",
  818 + "type-device-profile": "Device profile",
  819 + "type-device-profiles": "Device profiles",
  820 + "list-of-device-profiles": "{ count, plural, 1 {One device profile} other {List of # device profiles} }",
  821 + "device-profile-name-starts-with": "Device profiles whose names start with '{{prefix}}'",
809 "type-asset": "Asset", 822 "type-asset": "Asset",
810 "type-assets": "Assets", 823 "type-assets": "Assets",
811 "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", 824 "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }",
@@ -826,6 +839,10 @@ @@ -826,6 +839,10 @@
826 "type-tenants": "Tenants", 839 "type-tenants": "Tenants",
827 "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", 840 "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }",
828 "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", 841 "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'",
  842 + "type-tenant-profile": "Tenant profile",
  843 + "type-tenant-profiles": "Tenant profiles",
  844 + "list-of-tenant-profiles": "{ count, plural, 1 {One tenant profile} other {List of # tenant profiles} }",
  845 + "tenant-profile-name-starts-with": "Tenant profiles whose names start with '{{prefix}}'",
829 "type-customer": "Customer", 846 "type-customer": "Customer",
830 "type-customers": "Customers", 847 "type-customers": "Customers",
831 "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", 848 "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }",
@@ -1659,6 +1676,15 @@ @@ -1659,6 +1676,15 @@
1659 "isolated-tb-core-details": "Requires separate microservice(s) per isolated Tenant", 1676 "isolated-tb-core-details": "Requires separate microservice(s) per isolated Tenant",
1660 "isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant" 1677 "isolated-tb-rule-engine-details": "Requires separate microservice(s) per isolated Tenant"
1661 }, 1678 },
  1679 + "tenant-profile": {
  1680 + "tenant-profile": "Tenant profile",
  1681 + "tenant-profiles": "Tenant profiles",
  1682 + "add": "Add tenant profile",
  1683 + "tenant-profile-details": "Tenant profile details",
  1684 + "no-tenant-profiles-text": "No tenant profiles found",
  1685 + "search": "Search tenant profiles",
  1686 + "selected-tenant-profiles": "{ count, plural, 1 {1 tenant profile} other {# tenant profiles} } selected"
  1687 + },
1662 "timeinterval": { 1688 "timeinterval": {
1663 "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", 1689 "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }",
1664 "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }", 1690 "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }",
@@ -2059,4 +2085,4 @@ @@ -2059,4 +2085,4 @@
2059 "ka_GE": "ქართული" 2085 "ka_GE": "ქართული"
2060 } 2086 }
2061 } 2087 }
2062 -} 2088 +},