Showing
16 changed files
with
271 additions
and
46 deletions
... | ... | @@ -20,7 +20,7 @@ import { Observable } from 'rxjs'; |
20 | 20 | import { HttpClient } from '@angular/common/http'; |
21 | 21 | import { PageLink } from '@shared/models/page/page-link'; |
22 | 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 | 25 | @Injectable({ |
26 | 26 | providedIn: 'root' |
... | ... | @@ -35,10 +35,18 @@ export class TenantService { |
35 | 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 | 42 | public getTenant(tenantId: string, config?: RequestConfig): Observable<Tenant> { |
39 | 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 | 50 | public saveTenant(tenant: Tenant, config?: RequestConfig): Observable<Tenant> { |
43 | 51 | return this.http.post<Tenant>('/api/tenant', tenant, defaultHttpOptionsFromConfig(config)); |
44 | 52 | } | ... | ... |
... | ... | @@ -70,8 +70,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { |
70 | 70 | return this.fb.group( |
71 | 71 | { |
72 | 72 | name: [entity ? entity.name : '', [Validators.required]], |
73 | + deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], | |
73 | 74 | type: [entity ? entity.type : null, [Validators.required]], |
74 | 75 | label: [entity ? entity.label : ''], |
76 | + deviceData: [entity ? entity.deviceData : null, [Validators.required]], | |
75 | 77 | additionalInfo: this.fb.group( |
76 | 78 | { |
77 | 79 | gateway: [entity && entity.additionalInfo ? entity.additionalInfo.gateway : false], |
... | ... | @@ -84,8 +86,10 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> { |
84 | 86 | |
85 | 87 | updateForm(entity: DeviceInfo) { |
86 | 88 | this.entityForm.patchValue({name: entity.name}); |
89 | + this.entityForm.patchValue({deviceProfileId: entity.deviceProfileId}); | |
87 | 90 | this.entityForm.patchValue({type: entity.type}); |
88 | 91 | this.entityForm.patchValue({label: entity.label}); |
92 | + this.entityForm.patchValue({deviceData: entity.deviceData}); | |
89 | 93 | this.entityForm.patchValue({additionalInfo: |
90 | 94 | {gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false}}); |
91 | 95 | this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); | ... | ... |
... | ... | @@ -150,13 +150,14 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev |
150 | 150 | configureColumns(deviceScope: string): Array<EntityTableColumn<DeviceInfo>> { |
151 | 151 | const columns: Array<EntityTableColumn<DeviceInfo>> = [ |
152 | 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 | 158 | if (deviceScope === 'tenant') { |
158 | 159 | columns.push( |
159 | - new EntityTableColumn<DeviceInfo>('customerTitle', 'customer.customer', '25%'), | |
160 | + new EntityTableColumn<DeviceInfo>('customerTitle', 'customer.customer', '20%'), | |
160 | 161 | new EntityTableColumn<DeviceInfo>('customerIsPublic', 'device.public', '60px', |
161 | 162 | entity => { |
162 | 163 | return checkBoxCell(entity.customerIsPublic); | ... | ... |
... | ... | @@ -18,14 +18,14 @@ import { Component } from '@angular/core'; |
18 | 18 | import { Store } from '@ngrx/store'; |
19 | 19 | import { AppState } from '@core/core.state'; |
20 | 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 | 23 | @Component({ |
24 | 24 | selector: 'tb-tenant-tabs', |
25 | 25 | templateUrl: './tenant-tabs.component.html', |
26 | 26 | styleUrls: [] |
27 | 27 | }) |
28 | -export class TenantTabsComponent extends EntityTabsComponent<Tenant> { | |
28 | +export class TenantTabsComponent extends EntityTabsComponent<TenantInfo> { | |
29 | 29 | |
30 | 30 | constructor(protected store: Store<AppState>) { |
31 | 31 | super(store); | ... | ... |
... | ... | @@ -18,7 +18,7 @@ import { Component, Inject } from '@angular/core'; |
18 | 18 | import { Store } from '@ngrx/store'; |
19 | 19 | import { AppState } from '@core/core.state'; |
20 | 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 | 22 | import { ActionNotificationShow } from '@app/core/notification/notification.actions'; |
23 | 23 | import { TranslateService } from '@ngx-translate/core'; |
24 | 24 | import { ContactBasedComponent } from '../../components/entity/contact-based.component'; |
... | ... | @@ -29,12 +29,12 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod |
29 | 29 | templateUrl: './tenant.component.html', |
30 | 30 | styleUrls: ['./tenant.component.scss'] |
31 | 31 | }) |
32 | -export class TenantComponent extends ContactBasedComponent<Tenant> { | |
32 | +export class TenantComponent extends ContactBasedComponent<TenantInfo> { | |
33 | 33 | |
34 | 34 | constructor(protected store: Store<AppState>, |
35 | 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 | 38 | protected fb: FormBuilder) { |
39 | 39 | super(store, fb, entityValue, entitiesTableConfigValue); |
40 | 40 | } |
... | ... | @@ -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 | 51 | return this.fb.group( |
52 | 52 | { |
53 | 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 | 57 | additionalInfo: this.fb.group( |
57 | 58 | { |
58 | 59 | description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''] |
... | ... | @@ -64,8 +65,9 @@ export class TenantComponent extends ContactBasedComponent<Tenant> { |
64 | 65 | |
65 | 66 | updateEntityForm(entity: Tenant) { |
66 | 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 | 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 | 75 | if (this.entityForm) { |
74 | 76 | if (this.isEditValue) { |
75 | 77 | this.entityForm.enable({emitEvent: false}); |
76 | - if (!this.isAdd) { | |
78 | + /* if (!this.isAdd) { | |
77 | 79 | this.entityForm.get('isolatedTbCore').disable({emitEvent: false}); |
78 | 80 | this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false}); |
79 | - } | |
81 | + } */ | |
80 | 82 | } else { |
81 | 83 | this.entityForm.disable({emitEvent: false}); |
82 | 84 | } | ... | ... |
... | ... | @@ -18,7 +18,7 @@ import { Injectable } from '@angular/core'; |
18 | 18 | |
19 | 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 | 22 | import { |
23 | 23 | DateEntityTableColumn, |
24 | 24 | EntityTableColumn, |
... | ... | @@ -31,11 +31,12 @@ import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared |
31 | 31 | import { TenantComponent } from '@modules/home/pages/tenant/tenant.component'; |
32 | 32 | import { EntityAction } from '@home/models/entity/entity-component.models'; |
33 | 33 | import { TenantTabsComponent } from '@home/pages/tenant/tenant-tabs.component'; |
34 | +import { mergeMap } from 'rxjs/operators'; | |
34 | 35 | |
35 | 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 | 41 | constructor(private tenantService: TenantService, |
41 | 42 | private translate: TranslateService, |
... | ... | @@ -49,11 +50,12 @@ export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Ten |
49 | 50 | this.config.entityResources = entityTypeResources.get(EntityType.TENANT); |
50 | 51 | |
51 | 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 | 61 | this.config.cellActionDescriptors.push( |
... | ... | @@ -70,27 +72,29 @@ export class TenantsTableConfigResolver implements Resolve<EntityTableConfig<Ten |
70 | 72 | this.config.deleteEntitiesTitle = count => this.translate.instant('tenant.delete-tenants-title', {count}); |
71 | 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 | 80 | this.config.deleteEntity = id => this.tenantService.deleteTenant(id.id); |
77 | 81 | this.config.onEntityAction = action => this.onTenantAction(action); |
78 | 82 | } |
79 | 83 | |
80 | - resolve(): EntityTableConfig<Tenant> { | |
84 | + resolve(): EntityTableConfig<TenantInfo> { | |
81 | 85 | this.config.tableTitle = this.translate.instant('tenant.tenants'); |
82 | 86 | |
83 | 87 | return this.config; |
84 | 88 | } |
85 | 89 | |
86 | - manageTenantAdmins($event: Event, tenant: Tenant) { | |
90 | + manageTenantAdmins($event: Event, tenant: TenantInfo) { | |
87 | 91 | if ($event) { |
88 | 92 | $event.stopPropagation(); |
89 | 93 | } |
90 | 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 | 98 | switch (action.action) { |
95 | 99 | case 'manageTenantAdmins': |
96 | 100 | this.manageTenantAdmins(action.event, action.entity); | ... | ... |
... | ... | @@ -107,9 +107,11 @@ export const HelpLinks = { |
107 | 107 | ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node', |
108 | 108 | ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node', |
109 | 109 | tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', |
110 | + tenantProfiles: helpBaseUrl + '/docs/user-guide/ui/tenant-profiles', | |
110 | 111 | customers: helpBaseUrl + '/docs/user-guide/ui/customers', |
111 | 112 | users: helpBaseUrl + '/docs/user-guide/ui/users', |
112 | 113 | devices: helpBaseUrl + '/docs/user-guide/ui/devices', |
114 | + deviceProfiles: helpBaseUrl + '/docs/user-guide/ui/device-profiles', | |
113 | 115 | assets: helpBaseUrl + '/docs/user-guide/ui/assets', |
114 | 116 | entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views', |
115 | 117 | entitiesImport: helpBaseUrl + '/docs/user-guide/bulk-provisioning', | ... | ... |
... | ... | @@ -20,6 +20,62 @@ import { TenantId } from '@shared/models/id/tenant-id'; |
20 | 20 | import { CustomerId } from '@shared/models/id/customer-id'; |
21 | 21 | import { DeviceCredentialsId } from '@shared/models/id/device-credentials-id'; |
22 | 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 | 80 | export interface Device extends BaseData<DeviceId> { |
25 | 81 | tenantId?: TenantId; |
... | ... | @@ -27,12 +83,15 @@ export interface Device extends BaseData<DeviceId> { |
27 | 83 | name: string; |
28 | 84 | type: string; |
29 | 85 | label: string; |
86 | + deviceProfileId: DeviceProfileId; | |
87 | + deviceData: DeviceData; | |
30 | 88 | additionalInfo?: any; |
31 | 89 | } |
32 | 90 | |
33 | 91 | export interface DeviceInfo extends Device { |
34 | 92 | customerTitle: string; |
35 | 93 | customerIsPublic: boolean; |
94 | + deviceProfileName: string; | |
36 | 95 | } |
37 | 96 | |
38 | 97 | export enum DeviceCredentialsType { |
... | ... | @@ -69,6 +128,6 @@ export enum ClaimResponse { |
69 | 128 | } |
70 | 129 | |
71 | 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 | 35 | |
36 | 36 | export enum EntityType { |
37 | 37 | TENANT = 'TENANT', |
38 | + TENANT_PROFILE = 'TENANT_PROFILE', | |
38 | 39 | CUSTOMER = 'CUSTOMER', |
39 | 40 | USER = 'USER', |
40 | 41 | DASHBOARD = 'DASHBOARD', |
41 | 42 | ASSET = 'ASSET', |
42 | 43 | DEVICE = 'DEVICE', |
44 | + DEVICE_PROFILE = 'DEVICE_PROFILE', | |
43 | 45 | ALARM = 'ALARM', |
44 | 46 | RULE_CHAIN = 'RULE_CHAIN', |
45 | 47 | RULE_NODE = 'RULE_NODE', |
... | ... | @@ -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 | 108 | EntityType.CUSTOMER, |
93 | 109 | { |
94 | 110 | type: 'entity.type-customer', |
... | ... | @@ -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 | 164 | EntityType.ASSET, |
135 | 165 | { |
136 | 166 | type: 'entity.type-asset', |
... | ... | @@ -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 | 297 | EntityType.CUSTOMER, |
262 | 298 | { |
263 | 299 | helpLinkId: 'customers' |
... | ... | @@ -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 | 321 | EntityType.ASSET, |
280 | 322 | { |
281 | 323 | helpLinkId: 'assets' | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | |
17 | 17 | import { EntityType } from '@shared/models/entity-type.models'; |
18 | 18 | import { AttributeData } from './telemetry/telemetry.models'; |
19 | +import { EntityId } from '@shared/models/id/entity-id'; | |
19 | 20 | |
20 | 21 | export interface EntityInfo { |
21 | 22 | name?: string; |
... | ... | @@ -25,6 +26,11 @@ export interface EntityInfo { |
25 | 26 | entityDescription?: string; |
26 | 27 | } |
27 | 28 | |
29 | +export interface EntityInfoData { | |
30 | + id: EntityId; | |
31 | + name: string; | |
32 | +} | |
33 | + | |
28 | 34 | export interface ImportEntityData { |
29 | 35 | name: string; |
30 | 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 | 21 | export * from './dashboard-id'; |
22 | 22 | export * from './device-credentials-id'; |
23 | 23 | export * from './device-id'; |
24 | +export * from './device-profile-id'; | |
24 | 25 | export * from './entity-id'; |
25 | 26 | export * from './entity-view-id'; |
26 | 27 | export * from './event-id'; |
... | ... | @@ -28,6 +29,7 @@ export * from './has-uuid'; |
28 | 29 | export * from './rule-chain-id'; |
29 | 30 | export * from './rule-node-id'; |
30 | 31 | export * from './tenant-id'; |
32 | +export * from './tenant-profile-id'; | |
31 | 33 | export * from './user-id'; |
32 | 34 | export * from './widget-type-id'; |
33 | 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 | 50 | case EntityKeyType.CLIENT_ATTRIBUTE: |
51 | 51 | case EntityKeyType.SHARED_ATTRIBUTE: |
52 | 52 | case EntityKeyType.SERVER_ATTRIBUTE: |
53 | - return DataKeyType.attribute | |
53 | + return DataKeyType.attribute; | |
54 | 54 | case EntityKeyType.TIME_SERIES: |
55 | 55 | return DataKeyType.timeseries; |
56 | 56 | case EntityKeyType.ENTITY_FIELD: |
... | ... | @@ -81,11 +81,10 @@ export interface EntityKey { |
81 | 81 | } |
82 | 82 | |
83 | 83 | export function dataKeyToEntityKey(dataKey: DataKey): EntityKey { |
84 | - const entityKey: EntityKey = { | |
84 | + return { | |
85 | 85 | key: dataKey.name, |
86 | 86 | type: dataKeyTypeToEntityKeyType(dataKey.type) |
87 | 87 | }; |
88 | - return entityKey; | |
89 | 88 | } |
90 | 89 | |
91 | 90 | export enum EntityKeyValueType { |
... | ... | @@ -287,26 +286,26 @@ export interface FilterPredicateValue<T> { |
287 | 286 | } |
288 | 287 | |
289 | 288 | export interface StringFilterPredicate { |
290 | - type: FilterPredicateType.STRING, | |
289 | + type: FilterPredicateType.STRING; | |
291 | 290 | operation: StringOperation; |
292 | 291 | value: FilterPredicateValue<string>; |
293 | 292 | ignoreCase: boolean; |
294 | 293 | } |
295 | 294 | |
296 | 295 | export interface NumericFilterPredicate { |
297 | - type: FilterPredicateType.NUMERIC, | |
296 | + type: FilterPredicateType.NUMERIC; | |
298 | 297 | operation: NumericOperation; |
299 | 298 | value: FilterPredicateValue<number>; |
300 | 299 | } |
301 | 300 | |
302 | 301 | export interface BooleanFilterPredicate { |
303 | - type: FilterPredicateType.BOOLEAN, | |
302 | + type: FilterPredicateType.BOOLEAN; | |
304 | 303 | operation: BooleanOperation; |
305 | 304 | value: FilterPredicateValue<boolean>; |
306 | 305 | } |
307 | 306 | |
308 | 307 | export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> { |
309 | - type: FilterPredicateType.COMPLEX, | |
308 | + type: FilterPredicateType.COMPLEX; | |
310 | 309 | operation: ComplexOperation; |
311 | 310 | predicates: Array<T>; |
312 | 311 | } |
... | ... | @@ -481,7 +480,7 @@ export interface Filter extends FilterInfo { |
481 | 480 | } |
482 | 481 | |
483 | 482 | export interface Filters { |
484 | - [id: string]: Filter | |
483 | + [id: string]: Filter; | |
485 | 484 | } |
486 | 485 | |
487 | 486 | export interface EntityFilter extends EntityFilters { |
... | ... | @@ -535,7 +534,7 @@ export function createDefaultEntityDataPageLink(pageSize: number): EntityDataPag |
535 | 534 | }, |
536 | 535 | direction: Direction.DESC |
537 | 536 | } |
538 | - } | |
537 | + }; | |
539 | 538 | } |
540 | 539 | |
541 | 540 | export const singleEntityDataPageLink: EntityDataPageLink = createDefaultEntityDataPageLink(1); | ... | ... |
... | ... | @@ -16,11 +16,29 @@ |
16 | 16 | |
17 | 17 | import { ContactBased } from '@shared/models/contact-based.model'; |
18 | 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 | 35 | export interface Tenant extends ContactBased<TenantId> { |
21 | 36 | title: string; |
22 | 37 | region: string; |
23 | - isolatedTbCore: boolean; | |
24 | - isolatedTbRuleEngine: boolean; | |
38 | + tenantProfileId: TenantProfileId; | |
25 | 39 | additionalInfo?: any; |
26 | 40 | } |
41 | + | |
42 | +export interface TenantInfo extends Tenant { | |
43 | + tenantProfileName: string; | |
44 | +} | ... | ... |
... | ... | @@ -750,6 +750,15 @@ |
750 | 750 | "search": "Search devices", |
751 | 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 | 762 | "dialog": { |
754 | 763 | "close": "Close dialog" |
755 | 764 | }, |
... | ... | @@ -806,6 +815,10 @@ |
806 | 815 | "type-devices": "Devices", |
807 | 816 | "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", |
808 | 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 | 822 | "type-asset": "Asset", |
810 | 823 | "type-assets": "Assets", |
811 | 824 | "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", |
... | ... | @@ -826,6 +839,10 @@ |
826 | 839 | "type-tenants": "Tenants", |
827 | 840 | "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", |
828 | 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 | 846 | "type-customer": "Customer", |
830 | 847 | "type-customers": "Customers", |
831 | 848 | "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", |
... | ... | @@ -1659,6 +1676,15 @@ |
1659 | 1676 | "isolated-tb-core-details": "Requires separate microservice(s) per isolated Tenant", |
1660 | 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 | 1688 | "timeinterval": { |
1663 | 1689 | "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", |
1664 | 1690 | "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }", |
... | ... | @@ -2059,4 +2085,4 @@ |
2059 | 2085 | "ka_GE": "ქართული" |
2060 | 2086 | } |
2061 | 2087 | } |
2062 | -} | |
2088 | +}, | ... | ... |