Showing
17 changed files
with
888 additions
and
7 deletions
@@ -71,7 +71,8 @@ export class AddEntitiesToCustomerDialogComponent extends PageComponent implemen | @@ -71,7 +71,8 @@ export class AddEntitiesToCustomerDialogComponent extends PageComponent implemen | ||
71 | this.assignToCustomerText = 'device.assign-device-to-customer-text'; | 71 | this.assignToCustomerText = 'device.assign-device-to-customer-text'; |
72 | break; | 72 | break; |
73 | case EntityType.ASSET: | 73 | case EntityType.ASSET: |
74 | - // TODO: | 74 | + this.assignToCustomerTitle = 'asset.assign-asset-to-customer'; |
75 | + this.assignToCustomerText = 'asset.assign-asset-to-customer-text'; | ||
75 | break; | 76 | break; |
76 | case EntityType.ENTITY_VIEW: | 77 | case EntityType.ENTITY_VIEW: |
77 | // TODO: | 78 | // TODO: |
@@ -70,7 +70,8 @@ export class AssignToCustomerDialogComponent extends PageComponent implements On | @@ -70,7 +70,8 @@ export class AssignToCustomerDialogComponent extends PageComponent implements On | ||
70 | this.assignToCustomerText = 'device.assign-to-customer-text'; | 70 | this.assignToCustomerText = 'device.assign-to-customer-text'; |
71 | break; | 71 | break; |
72 | case EntityType.ASSET: | 72 | case EntityType.ASSET: |
73 | - // TODO: | 73 | + this.assignToCustomerTitle = 'asset.assign-asset-to-customer'; |
74 | + this.assignToCustomerText = 'asset.assign-to-customer-text'; | ||
74 | break; | 75 | break; |
75 | case EntityType.ENTITY_VIEW: | 76 | case EntityType.ENTITY_VIEW: |
76 | // TODO: | 77 | // TODO: |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 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 {NgModule} from '@angular/core'; | ||
18 | +import {RouterModule, Routes} from '@angular/router'; | ||
19 | + | ||
20 | +import {EntitiesTableComponent} from '@shared/components/entity/entities-table.component'; | ||
21 | +import {Authority} from '@shared/models/authority.enum'; | ||
22 | +import {AssetsTableConfigResolver} from './assets-table-config.resolver'; | ||
23 | + | ||
24 | +const routes: Routes = [ | ||
25 | + { | ||
26 | + path: 'assets', | ||
27 | + component: EntitiesTableComponent, | ||
28 | + data: { | ||
29 | + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], | ||
30 | + title: 'asset.assets', | ||
31 | + assetsType: 'tenant', | ||
32 | + breadcrumb: { | ||
33 | + label: 'asset.assets', | ||
34 | + icon: 'domain' | ||
35 | + } | ||
36 | + }, | ||
37 | + resolve: { | ||
38 | + entitiesTableConfig: AssetsTableConfigResolver | ||
39 | + } | ||
40 | + } | ||
41 | +]; | ||
42 | + | ||
43 | +@NgModule({ | ||
44 | + imports: [RouterModule.forChild(routes)], | ||
45 | + exports: [RouterModule], | ||
46 | + providers: [ | ||
47 | + AssetsTableConfigResolver | ||
48 | + ] | ||
49 | +}) | ||
50 | +export class AssetRoutingModule { } |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<tb-entity-subtype-select | ||
19 | + [showLabel]="true" | ||
20 | + [entityType]="entityType.ASSET" | ||
21 | + [ngModel]="entitiesTableConfig.componentsData.assetType" | ||
22 | + (ngModelChange)="assetTypeChanged($event)"> | ||
23 | +</tb-entity-subtype-select> |
1 | +/** | ||
2 | + * Copyright © 2016-2019 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 | +:host { | ||
17 | + flex: 1; | ||
18 | + display: flex; | ||
19 | + justify-content: flex-start; | ||
20 | +} | ||
21 | + | ||
22 | +:host ::ng-deep { | ||
23 | + tb-entity-subtype-select { | ||
24 | + mat-form-field { | ||
25 | + font-size: 16px; | ||
26 | + | ||
27 | + .mat-form-field-wrapper { | ||
28 | + padding-bottom: 0; | ||
29 | + } | ||
30 | + | ||
31 | + .mat-form-field-underline { | ||
32 | + bottom: 0; | ||
33 | + } | ||
34 | + } | ||
35 | + } | ||
36 | +} |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 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 {Component} from '@angular/core'; | ||
18 | +import {Store} from '@ngrx/store'; | ||
19 | +import {AppState} from '@core/core.state'; | ||
20 | +import {EntityTableHeaderComponent} from '@shared/components/entity/entity-table-header.component'; | ||
21 | +import {EntityType} from '@shared/models/entity-type.models'; | ||
22 | +import {AssetInfo} from '@shared/models/asset.models'; | ||
23 | + | ||
24 | +@Component({ | ||
25 | + selector: 'tb-asset-table-header', | ||
26 | + templateUrl: './asset-table-header.component.html', | ||
27 | + styleUrls: ['./asset-table-header.component.scss'] | ||
28 | +}) | ||
29 | +export class AssetTableHeaderComponent extends EntityTableHeaderComponent<AssetInfo> { | ||
30 | + | ||
31 | + entityType = EntityType; | ||
32 | + | ||
33 | + constructor(protected store: Store<AppState>) { | ||
34 | + super(store); | ||
35 | + } | ||
36 | + | ||
37 | + assetTypeChanged(assetType: string) { | ||
38 | + this.entitiesTableConfig.componentsData.assetType = assetType; | ||
39 | + this.entitiesTableConfig.table.updateData(); | ||
40 | + } | ||
41 | + | ||
42 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<div class="tb-details-buttons"> | ||
19 | + <button mat-raised-button color="primary" | ||
20 | + [disabled]="(isLoading$ | async)" | ||
21 | + (click)="onEntityAction($event, 'makePublic')" | ||
22 | + [fxShow]="!isEdit && assetScope === 'tenant' && !isAssignedToCustomer(entity) && !entity?.customerIsPublic"> | ||
23 | + {{'asset.make-public' | translate }} | ||
24 | + </button> | ||
25 | + <button mat-raised-button color="primary" | ||
26 | + [disabled]="(isLoading$ | async)" | ||
27 | + (click)="onEntityAction($event, 'assignToCustomer')" | ||
28 | + [fxShow]="!isEdit && assetScope === 'tenant' && !isAssignedToCustomer(entity)"> | ||
29 | + {{'asset.assign-to-customer' | translate }} | ||
30 | + </button> | ||
31 | + <button mat-raised-button color="primary" | ||
32 | + [disabled]="(isLoading$ | async)" | ||
33 | + (click)="onEntityAction($event, 'unassignFromCustomer')" | ||
34 | + [fxShow]="!isEdit && (assetScope === 'customer' || assetScope === 'tenant') && isAssignedToCustomer(entity)"> | ||
35 | + {{ (entity?.customerIsPublic ? 'asset.make-private' : 'asset.unassign-from-customer') | translate }} | ||
36 | + </button> | ||
37 | + <button mat-raised-button color="primary" | ||
38 | + [disabled]="(isLoading$ | async)" | ||
39 | + (click)="onEntityAction($event, 'delete')" | ||
40 | + [fxShow]="!hideDelete() && !isEdit"> | ||
41 | + {{'asset.delete' | translate }} | ||
42 | + </button> | ||
43 | + <div fxLayout="row"> | ||
44 | + <button mat-raised-button | ||
45 | + ngxClipboard | ||
46 | + (cbOnSuccess)="onAssetIdCopied($event)" | ||
47 | + [cbContent]="entity?.id?.id" | ||
48 | + [fxShow]="!isEdit"> | ||
49 | + <mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon> | ||
50 | + <span translate>asset.copyId</span> | ||
51 | + </button> | ||
52 | + </div> | ||
53 | +</div> | ||
54 | +<div class="mat-padding" fxLayout="column"> | ||
55 | + <mat-form-field class="mat-block" | ||
56 | + [fxShow]="!isEdit && isAssignedToCustomer(entity) | ||
57 | + && !entity?.customerIsPublic && assetScope === 'tenant'"> | ||
58 | + <mat-label translate>asset.assignedToCustomer</mat-label> | ||
59 | + <input matInput disabled [ngModel]="entity?.customerTitle"> | ||
60 | + </mat-form-field> | ||
61 | + <div class="tb-small" style="padding-bottom: 10px; padding-left: 2px;" | ||
62 | + [fxShow]="!isEdit && entity?.customerIsPublic && (assetScope === 'customer' || assetScope === 'tenant')"> | ||
63 | + {{ 'asset.asset-public' | translate }} | ||
64 | + </div> | ||
65 | + <form #entityNgForm="ngForm" [formGroup]="entityForm"> | ||
66 | + <fieldset [disabled]="(isLoading$ | async) || !isEdit"> | ||
67 | + <mat-form-field class="mat-block"> | ||
68 | + <mat-label translate>asset.name</mat-label> | ||
69 | + <input matInput formControlName="name" required> | ||
70 | + <mat-error *ngIf="entityForm.get('name').hasError('required')"> | ||
71 | + {{ 'asset.name-required' | translate }} | ||
72 | + </mat-error> | ||
73 | + </mat-form-field> | ||
74 | + <tb-entity-subtype-autocomplete | ||
75 | + formControlName="type" | ||
76 | + [required]="true" | ||
77 | + [entityType]="entityType.ASSET" | ||
78 | + > | ||
79 | + </tb-entity-subtype-autocomplete> | ||
80 | + <div formGroupName="additionalInfo"> | ||
81 | + <mat-form-field class="mat-block"> | ||
82 | + <mat-label translate>asset.description</mat-label> | ||
83 | + <textarea matInput formControlName="description" rows="2"></textarea> | ||
84 | + </mat-form-field> | ||
85 | + </div> | ||
86 | + </fieldset> | ||
87 | + </form> | ||
88 | +</div> |
1 | +/** | ||
2 | + * Copyright © 2016-2019 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 | +:host { | ||
18 | + | ||
19 | +} |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 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 {Component} from '@angular/core'; | ||
18 | +import {Store} from '@ngrx/store'; | ||
19 | +import {AppState} from '@core/core.state'; | ||
20 | +import {EntityComponent} from '@shared/components/entity/entity.component'; | ||
21 | +import {FormBuilder, FormGroup, Validators} from '@angular/forms'; | ||
22 | +import {EntityType} from '@shared/models/entity-type.models'; | ||
23 | +import {NULL_UUID} from '@shared/models/id/has-uuid'; | ||
24 | +import {ActionNotificationShow} from '@core/notification/notification.actions'; | ||
25 | +import {TranslateService} from '@ngx-translate/core'; | ||
26 | +import {AssetInfo} from '@app/shared/models/asset.models'; | ||
27 | + | ||
28 | +@Component({ | ||
29 | + selector: 'tb-asset', | ||
30 | + templateUrl: './asset.component.html', | ||
31 | + styleUrls: ['./asset.component.scss'] | ||
32 | +}) | ||
33 | +export class AssetComponent extends EntityComponent<AssetInfo> { | ||
34 | + | ||
35 | + entityType = EntityType; | ||
36 | + | ||
37 | + assetScope: 'tenant' | 'customer' | 'customer_user'; | ||
38 | + | ||
39 | + constructor(protected store: Store<AppState>, | ||
40 | + protected translate: TranslateService, | ||
41 | + public fb: FormBuilder) { | ||
42 | + super(store); | ||
43 | + } | ||
44 | + | ||
45 | + ngOnInit() { | ||
46 | + this.assetScope = this.entitiesTableConfig.componentsData.assetScope; | ||
47 | + super.ngOnInit(); | ||
48 | + } | ||
49 | + | ||
50 | + hideDelete() { | ||
51 | + if (this.entitiesTableConfig) { | ||
52 | + return !this.entitiesTableConfig.deleteEnabled(this.entity); | ||
53 | + } else { | ||
54 | + return false; | ||
55 | + } | ||
56 | + } | ||
57 | + | ||
58 | + isAssignedToCustomer(entity: AssetInfo): boolean { | ||
59 | + return entity && entity.customerId && entity.customerId.id !== NULL_UUID; | ||
60 | + } | ||
61 | + | ||
62 | + buildForm(entity: AssetInfo): FormGroup { | ||
63 | + return this.fb.group( | ||
64 | + { | ||
65 | + name: [entity ? entity.name : '', [Validators.required]], | ||
66 | + type: [entity ? entity.type : null, [Validators.required]], | ||
67 | + additionalInfo: this.fb.group( | ||
68 | + { | ||
69 | + description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], | ||
70 | + } | ||
71 | + ) | ||
72 | + } | ||
73 | + ); | ||
74 | + } | ||
75 | + | ||
76 | + updateForm(entity: AssetInfo) { | ||
77 | + this.entityForm.patchValue({name: entity.name}); | ||
78 | + this.entityForm.patchValue({type: entity.type}); | ||
79 | + this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); | ||
80 | + } | ||
81 | + | ||
82 | + | ||
83 | + onAssetIdCopied($event) { | ||
84 | + this.store.dispatch(new ActionNotificationShow( | ||
85 | + { | ||
86 | + message: this.translate.instant('asset.idCopiedMessage'), | ||
87 | + type: 'success', | ||
88 | + duration: 750, | ||
89 | + verticalPosition: 'bottom', | ||
90 | + horizontalPosition: 'right' | ||
91 | + })); | ||
92 | + } | ||
93 | +} |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 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 {NgModule} from '@angular/core'; | ||
18 | +import {CommonModule} from '@angular/common'; | ||
19 | +import {SharedModule} from '@shared/shared.module'; | ||
20 | +import {HomeDialogsModule} from '../../dialogs/home-dialogs.module'; | ||
21 | +import {AssetComponent} from './asset.component'; | ||
22 | +import {AssetTableHeaderComponent} from './asset-table-header.component'; | ||
23 | +import {AssetRoutingModule} from './asset-routing.module'; | ||
24 | + | ||
25 | +@NgModule({ | ||
26 | + entryComponents: [ | ||
27 | + AssetComponent, | ||
28 | + AssetTableHeaderComponent | ||
29 | + ], | ||
30 | + declarations: [ | ||
31 | + AssetComponent, | ||
32 | + AssetTableHeaderComponent | ||
33 | + ], | ||
34 | + imports: [ | ||
35 | + CommonModule, | ||
36 | + SharedModule, | ||
37 | + HomeDialogsModule, | ||
38 | + AssetRoutingModule | ||
39 | + ] | ||
40 | +}) | ||
41 | +export class AssetModule { } |
1 | +/// | ||
2 | +/// Copyright © 2016-2019 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 {Injectable} from '@angular/core'; | ||
18 | + | ||
19 | +import {ActivatedRouteSnapshot, Resolve, Router} from '@angular/router'; | ||
20 | +import { | ||
21 | + CellActionDescriptor, | ||
22 | + checkBoxCell, | ||
23 | + DateEntityTableColumn, | ||
24 | + EntityTableColumn, | ||
25 | + EntityTableConfig, | ||
26 | + GroupActionDescriptor, | ||
27 | + HeaderActionDescriptor | ||
28 | +} from '@shared/components/entity/entities-table-config.models'; | ||
29 | +import {TranslateService} from '@ngx-translate/core'; | ||
30 | +import {DatePipe} from '@angular/common'; | ||
31 | +import {EntityType, entityTypeResources, entityTypeTranslations} from '@shared/models/entity-type.models'; | ||
32 | +import {EntityAction} from '@shared/components/entity/entity-component.models'; | ||
33 | +import {forkJoin, Observable, of} from 'rxjs'; | ||
34 | +import {select, Store} from '@ngrx/store'; | ||
35 | +import {selectAuthUser} from '@core/auth/auth.selectors'; | ||
36 | +import {map, mergeMap, take, tap} from 'rxjs/operators'; | ||
37 | +import {AppState} from '@core/core.state'; | ||
38 | +import {Authority} from '@app/shared/models/authority.enum'; | ||
39 | +import {CustomerService} from '@core/http/customer.service'; | ||
40 | +import {Customer} from '@app/shared/models/customer.model'; | ||
41 | +import {NULL_UUID} from '@shared/models/id/has-uuid'; | ||
42 | +import {BroadcastService} from '@core/services/broadcast.service'; | ||
43 | +import {MatDialog} from '@angular/material'; | ||
44 | +import {DialogService} from '@core/services/dialog.service'; | ||
45 | +import { | ||
46 | + AssignToCustomerDialogComponent, | ||
47 | + AssignToCustomerDialogData | ||
48 | +} from '@modules/home/dialogs/assign-to-customer-dialog.component'; | ||
49 | +import { | ||
50 | + AddEntitiesToCustomerDialogComponent, | ||
51 | + AddEntitiesToCustomerDialogData | ||
52 | +} from '../../dialogs/add-entities-to-customer-dialog.component'; | ||
53 | +import {Asset, AssetInfo} from '@app/shared/models/asset.models'; | ||
54 | +import {AssetService} from '@app/core/http/asset.service'; | ||
55 | +import {AssetComponent} from '@modules/home/pages/asset/asset.component'; | ||
56 | +import {AssetTableHeaderComponent} from '@modules/home/pages/asset/asset-table-header.component'; | ||
57 | +import {AssetId} from '@app/shared/models/id/asset-id'; | ||
58 | + | ||
59 | +@Injectable() | ||
60 | +export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> { | ||
61 | + | ||
62 | + private readonly config: EntityTableConfig<AssetInfo> = new EntityTableConfig<AssetInfo>(); | ||
63 | + | ||
64 | + private customerId: string; | ||
65 | + | ||
66 | + constructor(private store: Store<AppState>, | ||
67 | + private broadcast: BroadcastService, | ||
68 | + private assetService: AssetService, | ||
69 | + private customerService: CustomerService, | ||
70 | + private dialogService: DialogService, | ||
71 | + private translate: TranslateService, | ||
72 | + private datePipe: DatePipe, | ||
73 | + private router: Router, | ||
74 | + private dialog: MatDialog) { | ||
75 | + | ||
76 | + this.config.entityType = EntityType.ASSET; | ||
77 | + this.config.entityComponent = AssetComponent; | ||
78 | + this.config.entityTranslations = entityTypeTranslations.get(EntityType.ASSET); | ||
79 | + this.config.entityResources = entityTypeResources.get(EntityType.ASSET); | ||
80 | + | ||
81 | + this.config.deleteEntityTitle = asset => this.translate.instant('asset.delete-asset-title', { assetName: asset.name }); | ||
82 | + this.config.deleteEntityContent = () => this.translate.instant('asset.delete-asset-text'); | ||
83 | + this.config.deleteEntitiesTitle = count => this.translate.instant('asset.delete-assets-title', {count}); | ||
84 | + this.config.deleteEntitiesContent = () => this.translate.instant('asset.delete-assets-text'); | ||
85 | + | ||
86 | + this.config.loadEntity = id => this.assetService.getAssetInfo(id.id); | ||
87 | + this.config.saveEntity = asset => { | ||
88 | + return this.assetService.saveAsset(asset).pipe( | ||
89 | + tap(() => { | ||
90 | + this.broadcast.broadcast('assetSaved'); | ||
91 | + }), | ||
92 | + mergeMap((savedAsset) => this.assetService.getAssetInfo(savedAsset.id.id) | ||
93 | + )); | ||
94 | + }; | ||
95 | + this.config.onEntityAction = action => this.onAssetAction(action); | ||
96 | + | ||
97 | + this.config.headerComponent = AssetTableHeaderComponent; | ||
98 | + | ||
99 | + } | ||
100 | + | ||
101 | + resolve(route: ActivatedRouteSnapshot): Observable<EntityTableConfig<AssetInfo>> { | ||
102 | + const routeParams = route.params; | ||
103 | + this.config.componentsData = { | ||
104 | + assetScope: route.data.assetsType, | ||
105 | + assetType: '' | ||
106 | + }; | ||
107 | + this.customerId = routeParams.customerId; | ||
108 | + return this.store.pipe(select(selectAuthUser), take(1)).pipe( | ||
109 | + tap((authUser) => { | ||
110 | + if (authUser.authority === Authority.CUSTOMER_USER) { | ||
111 | + this.config.componentsData.assetScope = 'customer_user'; | ||
112 | + this.customerId = authUser.customerId; | ||
113 | + } | ||
114 | + }), | ||
115 | + mergeMap(() => | ||
116 | + this.customerId ? this.customerService.getCustomer(this.customerId) : of(null as Customer) | ||
117 | + ), | ||
118 | + map((parentCustomer) => { | ||
119 | + if (parentCustomer) { | ||
120 | + if (parentCustomer.additionalInfo && parentCustomer.additionalInfo.isPublic) { | ||
121 | + this.config.tableTitle = this.translate.instant('customer.public-assets'); | ||
122 | + } else { | ||
123 | + this.config.tableTitle = parentCustomer.title + ': ' + this.translate.instant('asset.assets'); | ||
124 | + } | ||
125 | + } else { | ||
126 | + this.config.tableTitle = this.translate.instant('asset.assets'); | ||
127 | + } | ||
128 | + this.config.columns = this.configureColumns(this.config.componentsData.assetScope); | ||
129 | + this.configureEntityFunctions(this.config.componentsData.assetScope); | ||
130 | + this.config.cellActionDescriptors = this.configureCellActions(this.config.componentsData.assetScope); | ||
131 | + this.config.groupActionDescriptors = this.configureGroupActions(this.config.componentsData.assetScope); | ||
132 | + this.config.addActionDescriptors = this.configureAddActions(this.config.componentsData.assetScope); | ||
133 | + this.config.addEnabled = this.config.componentsData.assetScope !== 'customer_user'; | ||
134 | + this.config.entitiesDeleteEnabled = this.config.componentsData.assetScope === 'tenant'; | ||
135 | + this.config.deleteEnabled = () => this.config.componentsData.assetScope === 'tenant'; | ||
136 | + return this.config; | ||
137 | + }) | ||
138 | + ); | ||
139 | + } | ||
140 | + | ||
141 | + configureColumns(assetScope: string): Array<EntityTableColumn<AssetInfo>> { | ||
142 | + const columns: Array<EntityTableColumn<AssetInfo>> = [ | ||
143 | + new DateEntityTableColumn<AssetInfo>('createdTime', 'asset.created-time', this.datePipe, '150px'), | ||
144 | + new EntityTableColumn<AssetInfo>('name', 'asset.name'), | ||
145 | + new EntityTableColumn<AssetInfo>('type', 'asset.asset-type'), | ||
146 | + ]; | ||
147 | + if (assetScope === 'tenant') { | ||
148 | + columns.push( | ||
149 | + new EntityTableColumn<AssetInfo>('customerTitle', 'customer.customer'), | ||
150 | + new EntityTableColumn<AssetInfo>('customerIsPublic', 'asset.public', '60px', | ||
151 | + entity => { | ||
152 | + return checkBoxCell(entity.customerIsPublic); | ||
153 | + }, () => ({}), false), | ||
154 | + ); | ||
155 | + } | ||
156 | + return columns; | ||
157 | + } | ||
158 | + | ||
159 | + configureEntityFunctions(assetScope: string): void { | ||
160 | + if (assetScope === 'tenant') { | ||
161 | + this.config.entitiesFetchFunction = pageLink => | ||
162 | + this.assetService.getTenantAssetInfos(pageLink, this.config.componentsData.assetType); | ||
163 | + this.config.deleteEntity = id => this.assetService.deleteAsset(id.id); | ||
164 | + } else { | ||
165 | + this.config.entitiesFetchFunction = pageLink => | ||
166 | + this.assetService.getCustomerAssetInfos(this.customerId, pageLink, this.config.componentsData.assetType); | ||
167 | + this.config.deleteEntity = id => this.assetService.unassignAssetFromCustomer(id.id); | ||
168 | + } | ||
169 | + } | ||
170 | + | ||
171 | + configureCellActions(assetScope: string): Array<CellActionDescriptor<AssetInfo>> { | ||
172 | + const actions: Array<CellActionDescriptor<AssetInfo>> = []; | ||
173 | + if (assetScope === 'tenant') { | ||
174 | + actions.push( | ||
175 | + { | ||
176 | + name: this.translate.instant('asset.make-public'), | ||
177 | + icon: 'share', | ||
178 | + isEnabled: (entity) => (!entity.customerId || entity.customerId.id === NULL_UUID), | ||
179 | + onAction: ($event, entity) => this.makePublic($event, entity) | ||
180 | + }, | ||
181 | + { | ||
182 | + name: this.translate.instant('asset.assign-to-customer'), | ||
183 | + icon: 'assignment_ind', | ||
184 | + isEnabled: (entity) => (!entity.customerId || entity.customerId.id === NULL_UUID), | ||
185 | + onAction: ($event, entity) => this.assignToCustomer($event, [entity.id]) | ||
186 | + }, | ||
187 | + { | ||
188 | + name: this.translate.instant('asset.unassign-from-customer'), | ||
189 | + icon: 'assignment_return', | ||
190 | + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && !entity.customerIsPublic), | ||
191 | + onAction: ($event, entity) => this.unassignFromCustomer($event, entity) | ||
192 | + }, | ||
193 | + { | ||
194 | + name: this.translate.instant('asset.make-private'), | ||
195 | + icon: 'reply', | ||
196 | + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && entity.customerIsPublic), | ||
197 | + onAction: ($event, entity) => this.unassignFromCustomer($event, entity) | ||
198 | + } | ||
199 | + ); | ||
200 | + } | ||
201 | + if (assetScope === 'customer') { | ||
202 | + actions.push( | ||
203 | + { | ||
204 | + name: this.translate.instant('asset.unassign-from-customer'), | ||
205 | + icon: 'assignment_return', | ||
206 | + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && !entity.customerIsPublic), | ||
207 | + onAction: ($event, entity) => this.unassignFromCustomer($event, entity) | ||
208 | + }, | ||
209 | + { | ||
210 | + name: this.translate.instant('asset.make-private'), | ||
211 | + icon: 'reply', | ||
212 | + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && entity.customerIsPublic), | ||
213 | + onAction: ($event, entity) => this.unassignFromCustomer($event, entity) | ||
214 | + } | ||
215 | + ); | ||
216 | + } | ||
217 | + return actions; | ||
218 | + } | ||
219 | + | ||
220 | + configureGroupActions(assetScope: string): Array<GroupActionDescriptor<AssetInfo>> { | ||
221 | + const actions: Array<GroupActionDescriptor<AssetInfo>> = []; | ||
222 | + if (assetScope === 'tenant') { | ||
223 | + actions.push( | ||
224 | + { | ||
225 | + name: this.translate.instant('asset.assign-assets'), | ||
226 | + icon: 'assignment_ind', | ||
227 | + isEnabled: true, | ||
228 | + onAction: ($event, entities) => this.assignToCustomer($event, entities.map((entity) => entity.id)) | ||
229 | + } | ||
230 | + ); | ||
231 | + } | ||
232 | + if (assetScope === 'customer') { | ||
233 | + actions.push( | ||
234 | + { | ||
235 | + name: this.translate.instant('asset.unassign-assets'), | ||
236 | + icon: 'assignment_return', | ||
237 | + isEnabled: true, | ||
238 | + onAction: ($event, entities) => this.unassignAssetsFromCustomer($event, entities) | ||
239 | + } | ||
240 | + ); | ||
241 | + } | ||
242 | + return actions; | ||
243 | + } | ||
244 | + | ||
245 | + configureAddActions(assetScope: string): Array<HeaderActionDescriptor> { | ||
246 | + const actions: Array<HeaderActionDescriptor> = []; | ||
247 | + if (assetScope === 'tenant') { | ||
248 | + actions.push( | ||
249 | + { | ||
250 | + name: this.translate.instant('asset.add-asset-text'), | ||
251 | + icon: 'insert_drive_file', | ||
252 | + isEnabled: () => true, | ||
253 | + onAction: ($event) => this.config.table.addEntity($event) | ||
254 | + }, | ||
255 | + { | ||
256 | + name: this.translate.instant('asset.import'), | ||
257 | + icon: 'file_upload', | ||
258 | + isEnabled: () => true, | ||
259 | + onAction: ($event) => this.importAssets($event) | ||
260 | + } | ||
261 | + ); | ||
262 | + } | ||
263 | + if (assetScope === 'customer') { | ||
264 | + actions.push( | ||
265 | + { | ||
266 | + name: this.translate.instant('asset.assign-new-asset'), | ||
267 | + icon: 'add', | ||
268 | + isEnabled: () => true, | ||
269 | + onAction: ($event) => this.addAssetsToCustomer($event) | ||
270 | + } | ||
271 | + ); | ||
272 | + } | ||
273 | + return actions; | ||
274 | + } | ||
275 | + | ||
276 | + importAssets($event: Event) { | ||
277 | + if ($event) { | ||
278 | + $event.stopPropagation(); | ||
279 | + } | ||
280 | + // TODO: | ||
281 | + } | ||
282 | + | ||
283 | + addAssetsToCustomer($event: Event) { | ||
284 | + if ($event) { | ||
285 | + $event.stopPropagation(); | ||
286 | + } | ||
287 | + this.dialog.open<AddEntitiesToCustomerDialogComponent, AddEntitiesToCustomerDialogData, | ||
288 | + boolean>(AddEntitiesToCustomerDialogComponent, { | ||
289 | + disableClose: true, | ||
290 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | ||
291 | + data: { | ||
292 | + customerId: this.customerId, | ||
293 | + entityType: EntityType.ASSET | ||
294 | + } | ||
295 | + }).afterClosed() | ||
296 | + .subscribe((res) => { | ||
297 | + if (res) { | ||
298 | + this.config.table.updateData(); | ||
299 | + } | ||
300 | + }); | ||
301 | + } | ||
302 | + | ||
303 | + makePublic($event: Event, asset: Asset) { | ||
304 | + if ($event) { | ||
305 | + $event.stopPropagation(); | ||
306 | + } | ||
307 | + this.dialogService.confirm( | ||
308 | + this.translate.instant('asset.make-public-asset-title', {assetName: asset.name}), | ||
309 | + this.translate.instant('asset.make-public-asset-text'), | ||
310 | + this.translate.instant('action.no'), | ||
311 | + this.translate.instant('action.yes'), | ||
312 | + true | ||
313 | + ).subscribe((res) => { | ||
314 | + if (res) { | ||
315 | + this.assetService.makeAssetPublic(asset.id.id).subscribe( | ||
316 | + () => { | ||
317 | + this.config.table.updateData(); | ||
318 | + } | ||
319 | + ); | ||
320 | + } | ||
321 | + } | ||
322 | + ); | ||
323 | + } | ||
324 | + | ||
325 | + assignToCustomer($event: Event, assetIds: Array<AssetId>) { | ||
326 | + if ($event) { | ||
327 | + $event.stopPropagation(); | ||
328 | + } | ||
329 | + this.dialog.open<AssignToCustomerDialogComponent, AssignToCustomerDialogData, | ||
330 | + boolean>(AssignToCustomerDialogComponent, { | ||
331 | + disableClose: true, | ||
332 | + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], | ||
333 | + data: { | ||
334 | + entityIds: assetIds, | ||
335 | + entityType: EntityType.ASSET | ||
336 | + } | ||
337 | + }).afterClosed() | ||
338 | + .subscribe((res) => { | ||
339 | + if (res) { | ||
340 | + this.config.table.updateData(); | ||
341 | + } | ||
342 | + }); | ||
343 | + } | ||
344 | + | ||
345 | + unassignFromCustomer($event: Event, asset: AssetInfo) { | ||
346 | + if ($event) { | ||
347 | + $event.stopPropagation(); | ||
348 | + } | ||
349 | + const isPublic = asset.customerIsPublic; | ||
350 | + let title; | ||
351 | + let content; | ||
352 | + if (isPublic) { | ||
353 | + title = this.translate.instant('asset.make-private-asset-title', {assetName: asset.name}); | ||
354 | + content = this.translate.instant('asset.make-private-asset-text'); | ||
355 | + } else { | ||
356 | + title = this.translate.instant('asset.unassign-asset-title', {assetName: asset.name}); | ||
357 | + content = this.translate.instant('asset.unassign-asset-text'); | ||
358 | + } | ||
359 | + this.dialogService.confirm( | ||
360 | + title, | ||
361 | + content, | ||
362 | + this.translate.instant('action.no'), | ||
363 | + this.translate.instant('action.yes'), | ||
364 | + true | ||
365 | + ).subscribe((res) => { | ||
366 | + if (res) { | ||
367 | + this.assetService.unassignAssetFromCustomer(asset.id.id).subscribe( | ||
368 | + () => { | ||
369 | + this.config.table.updateData(); | ||
370 | + } | ||
371 | + ); | ||
372 | + } | ||
373 | + } | ||
374 | + ); | ||
375 | + } | ||
376 | + | ||
377 | + unassignAssetsFromCustomer($event: Event, assets: Array<AssetInfo>) { | ||
378 | + if ($event) { | ||
379 | + $event.stopPropagation(); | ||
380 | + } | ||
381 | + this.dialogService.confirm( | ||
382 | + this.translate.instant('asset.unassign-assets-title', {count: assets.length}), | ||
383 | + this.translate.instant('asset.unassign-assets-text'), | ||
384 | + this.translate.instant('action.no'), | ||
385 | + this.translate.instant('action.yes'), | ||
386 | + true | ||
387 | + ).subscribe((res) => { | ||
388 | + if (res) { | ||
389 | + const tasks: Observable<any>[] = []; | ||
390 | + assets.forEach( | ||
391 | + (asset) => { | ||
392 | + tasks.push(this.assetService.unassignAssetFromCustomer(asset.id.id)); | ||
393 | + } | ||
394 | + ); | ||
395 | + forkJoin(tasks).subscribe( | ||
396 | + () => { | ||
397 | + this.config.table.updateData(); | ||
398 | + } | ||
399 | + ); | ||
400 | + } | ||
401 | + } | ||
402 | + ); | ||
403 | + } | ||
404 | + | ||
405 | + onAssetAction(action: EntityAction<AssetInfo>): boolean { | ||
406 | + switch (action.action) { | ||
407 | + case 'makePublic': | ||
408 | + this.makePublic(action.event, action.entity); | ||
409 | + return true; | ||
410 | + case 'assignToCustomer': | ||
411 | + this.assignToCustomer(action.event, [action.entity.id]); | ||
412 | + return true; | ||
413 | + case 'unassignFromCustomer': | ||
414 | + this.unassignFromCustomer(action.event, action.entity); | ||
415 | + return true; | ||
416 | + } | ||
417 | + return false; | ||
418 | + } | ||
419 | + | ||
420 | +} |
@@ -22,6 +22,7 @@ import {Authority} from '@shared/models/authority.enum'; | @@ -22,6 +22,7 @@ import {Authority} from '@shared/models/authority.enum'; | ||
22 | import {UsersTableConfigResolver} from '../user/users-table-config.resolver'; | 22 | import {UsersTableConfigResolver} from '../user/users-table-config.resolver'; |
23 | import {CustomersTableConfigResolver} from './customers-table-config.resolver'; | 23 | import {CustomersTableConfigResolver} from './customers-table-config.resolver'; |
24 | import {DevicesTableConfigResolver} from '@modules/home/pages/device/devices-table-config.resolver'; | 24 | import {DevicesTableConfigResolver} from '@modules/home/pages/device/devices-table-config.resolver'; |
25 | +import {AssetsTableConfigResolver} from '../asset/assets-table-config.resolver'; | ||
25 | 26 | ||
26 | const routes: Routes = [ | 27 | const routes: Routes = [ |
27 | { | 28 | { |
@@ -74,6 +75,22 @@ const routes: Routes = [ | @@ -74,6 +75,22 @@ const routes: Routes = [ | ||
74 | resolve: { | 75 | resolve: { |
75 | entitiesTableConfig: DevicesTableConfigResolver | 76 | entitiesTableConfig: DevicesTableConfigResolver |
76 | } | 77 | } |
78 | + }, | ||
79 | + { | ||
80 | + path: ':customerId/assets', | ||
81 | + component: EntitiesTableComponent, | ||
82 | + data: { | ||
83 | + auth: [Authority.TENANT_ADMIN], | ||
84 | + title: 'customer.assets', | ||
85 | + assetsType: 'customer', | ||
86 | + breadcrumb: { | ||
87 | + label: 'customer.assets', | ||
88 | + icon: 'domain' | ||
89 | + } | ||
90 | + }, | ||
91 | + resolve: { | ||
92 | + entitiesTableConfig: AssetsTableConfigResolver | ||
93 | + } | ||
77 | } | 94 | } |
78 | ] | 95 | ] |
79 | } | 96 | } |
@@ -141,8 +141,8 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev | @@ -141,8 +141,8 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev | ||
141 | ); | 141 | ); |
142 | } | 142 | } |
143 | 143 | ||
144 | - configureColumns(deviceScope: string): Array<EntityTableColumn<Device | DeviceInfo>> { | ||
145 | - const columns: Array<EntityTableColumn<Device | DeviceInfo>> = [ | 144 | + configureColumns(deviceScope: string): Array<EntityTableColumn<DeviceInfo>> { |
145 | + const columns: Array<EntityTableColumn<DeviceInfo>> = [ | ||
146 | new DateEntityTableColumn<DeviceInfo>('createdTime', 'device.created-time', this.datePipe, '150px'), | 146 | new DateEntityTableColumn<DeviceInfo>('createdTime', 'device.created-time', this.datePipe, '150px'), |
147 | new EntityTableColumn<DeviceInfo>('name', 'device.name'), | 147 | new EntityTableColumn<DeviceInfo>('name', 'device.name'), |
148 | new EntityTableColumn<DeviceInfo>('type', 'device.device-type'), | 148 | new EntityTableColumn<DeviceInfo>('type', 'device.device-type'), |
@@ -24,6 +24,7 @@ import { CustomerModule } from '@modules/home/pages/customer/customer.module'; | @@ -24,6 +24,7 @@ import { CustomerModule } from '@modules/home/pages/customer/customer.module'; | ||
24 | // import { AuditLogModule } from '@modules/home/pages/audit-log/audit-log.module'; | 24 | // import { AuditLogModule } from '@modules/home/pages/audit-log/audit-log.module'; |
25 | import { UserModule } from '@modules/home/pages/user/user.module'; | 25 | import { UserModule } from '@modules/home/pages/user/user.module'; |
26 | import {DeviceModule} from '@modules/home/pages/device/device.module'; | 26 | import {DeviceModule} from '@modules/home/pages/device/device.module'; |
27 | +import {AssetModule} from '@modules/home/pages/asset/asset.module'; | ||
27 | 28 | ||
28 | @NgModule({ | 29 | @NgModule({ |
29 | exports: [ | 30 | exports: [ |
@@ -32,6 +33,7 @@ import {DeviceModule} from '@modules/home/pages/device/device.module'; | @@ -32,6 +33,7 @@ import {DeviceModule} from '@modules/home/pages/device/device.module'; | ||
32 | ProfileModule, | 33 | ProfileModule, |
33 | TenantModule, | 34 | TenantModule, |
34 | DeviceModule, | 35 | DeviceModule, |
36 | + AssetModule, | ||
35 | CustomerModule, | 37 | CustomerModule, |
36 | // AuditLogModule, | 38 | // AuditLogModule, |
37 | UserModule | 39 | UserModule |
@@ -60,7 +60,9 @@ export const HelpLinks = { | @@ -60,7 +60,9 @@ export const HelpLinks = { | ||
60 | tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', | 60 | tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', |
61 | customers: helpBaseUrl + '/docs/user-guide/customers', | 61 | customers: helpBaseUrl + '/docs/user-guide/customers', |
62 | users: helpBaseUrl + '/docs/user-guide/ui/users', | 62 | users: helpBaseUrl + '/docs/user-guide/ui/users', |
63 | - devices: helpBaseUrl + '/docs/user-guide/ui/devices' | 63 | + devices: helpBaseUrl + '/docs/user-guide/ui/devices', |
64 | + assets: helpBaseUrl + '/docs/user-guide/ui/assets', | ||
65 | + entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views' | ||
64 | } | 66 | } |
65 | }; | 67 | }; |
66 | 68 |
@@ -108,6 +108,34 @@ export const entityTypeTranslations = new Map<EntityType, EntityTypeTranslation> | @@ -108,6 +108,34 @@ export const entityTypeTranslations = new Map<EntityType, EntityTypeTranslation> | ||
108 | search: 'device.search', | 108 | search: 'device.search', |
109 | selectedEntities: 'device.selected-devices' | 109 | selectedEntities: 'device.selected-devices' |
110 | } | 110 | } |
111 | + ], | ||
112 | + [ | ||
113 | + EntityType.ASSET, | ||
114 | + { | ||
115 | + type: 'entity.type-asset', | ||
116 | + typePlural: 'entity.type-assets', | ||
117 | + list: 'entity.list-of-assets', | ||
118 | + nameStartsWith: 'entity.asset-name-starts-with', | ||
119 | + details: 'asset.asset-details', | ||
120 | + add: 'asset.add', | ||
121 | + noEntities: 'asset.no-assets-text', | ||
122 | + search: 'asset.search', | ||
123 | + selectedEntities: 'asset.selected-assets' | ||
124 | + } | ||
125 | + ], | ||
126 | + [ | ||
127 | + EntityType.ENTITY_VIEW, | ||
128 | + { | ||
129 | + type: 'entity.type-entity-view', | ||
130 | + typePlural: 'entity.type-entity-views', | ||
131 | + list: 'entity.list-of-entity-views', | ||
132 | + nameStartsWith: 'entity.entity-view-name-starts-with', | ||
133 | + details: 'entity-view.entity-view-details', | ||
134 | + add: 'entity-view.add', | ||
135 | + noEntities: 'entity-view.no-entity-views-text', | ||
136 | + search: 'entity-view.search', | ||
137 | + selectedEntities: 'entity-view.selected-entity-views' | ||
138 | + } | ||
111 | ] | 139 | ] |
112 | ] | 140 | ] |
113 | ); | 141 | ); |
@@ -137,6 +165,18 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource>( | @@ -137,6 +165,18 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource>( | ||
137 | { | 165 | { |
138 | helpLinkId: 'devices' | 166 | helpLinkId: 'devices' |
139 | } | 167 | } |
168 | + ], | ||
169 | + [ | ||
170 | + EntityType.ASSET, | ||
171 | + { | ||
172 | + helpLinkId: 'assets' | ||
173 | + } | ||
174 | + ], | ||
175 | + [ | ||
176 | + EntityType.ENTITY_VIEW, | ||
177 | + { | ||
178 | + helpLinkId: 'entityViews' | ||
179 | + } | ||
140 | ] | 180 | ] |
141 | ] | 181 | ] |
142 | ); | 182 | ); |
@@ -228,6 +228,7 @@ | @@ -228,6 +228,7 @@ | ||
228 | "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", | 228 | "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", |
229 | "asset-type-list-empty": "No asset types selected.", | 229 | "asset-type-list-empty": "No asset types selected.", |
230 | "asset-types": "Asset types", | 230 | "asset-types": "Asset types", |
231 | + "created-time": "Created time", | ||
231 | "name": "Name", | 232 | "name": "Name", |
232 | "name-required": "Name is required.", | 233 | "name-required": "Name is required.", |
233 | "description": "Description", | 234 | "description": "Description", |
@@ -264,7 +265,9 @@ | @@ -264,7 +265,9 @@ | ||
264 | "asset-required": "Asset is required", | 265 | "asset-required": "Asset is required", |
265 | "name-starts-with": "Asset name starts with", | 266 | "name-starts-with": "Asset name starts with", |
266 | "import": "Import assets", | 267 | "import": "Import assets", |
267 | - "asset-file": "Asset file" | 268 | + "asset-file": "Asset file", |
269 | + "search": "Search assets", | ||
270 | + "selected-assets": "{ count, plural, 1 {1 asset} other {# assets} } selected" | ||
268 | }, | 271 | }, |
269 | "attribute": { | 272 | "attribute": { |
270 | "attributes": "Attributes", | 273 | "attributes": "Attributes", |
@@ -867,6 +870,7 @@ | @@ -867,6 +870,7 @@ | ||
867 | "no-entity-view-types-matching": "No entity view types matching '{{entitySubtype}}' were found.", | 870 | "no-entity-view-types-matching": "No entity view types matching '{{entitySubtype}}' were found.", |
868 | "entity-view-type-list-empty": "No entity view types selected.", | 871 | "entity-view-type-list-empty": "No entity view types selected.", |
869 | "entity-view-types": "Entity View types", | 872 | "entity-view-types": "Entity View types", |
873 | + "created-time": "Created time", | ||
870 | "name": "Name", | 874 | "name": "Name", |
871 | "name-required": "Name is required.", | 875 | "name-required": "Name is required.", |
872 | "description": "Description", | 876 | "description": "Description", |
@@ -900,7 +904,9 @@ | @@ -900,7 +904,9 @@ | ||
900 | "make-public-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' public?", | 904 | "make-public-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' public?", |
901 | "make-public-entity-view-text": "After the confirmation the entity view and all its data will be made public and accessible by others.", | 905 | "make-public-entity-view-text": "After the confirmation the entity view and all its data will be made public and accessible by others.", |
902 | "make-private-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' private?", | 906 | "make-private-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' private?", |
903 | - "make-private-entity-view-text": "After the confirmation the entity view and all its data will be made private and won't be accessible by others." | 907 | + "make-private-entity-view-text": "After the confirmation the entity view and all its data will be made private and won't be accessible by others.", |
908 | + "search": "Search entity views", | ||
909 | + "selected-entity-views": "{ count, plural, 1 {1 entity view} other {# entity views} } selected" | ||
904 | }, | 910 | }, |
905 | "event": { | 911 | "event": { |
906 | "event-type": "Event type", | 912 | "event-type": "Event type", |