21 changed files with 810 additions and 31 deletions
@ -0,0 +1,67 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { PageLink } from '@shared/models/page/page-link'; |
|||
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; |
|||
import { Observable } from 'rxjs'; |
|||
import { PageData } from '@shared/models/page/page-data'; |
|||
import { TenantProfile } from '@shared/models/tenant.model'; |
|||
import { EntityInfoData } from '@shared/models/entity.models'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class TenantProfileService { |
|||
|
|||
constructor( |
|||
private http: HttpClient |
|||
) { } |
|||
|
|||
public getTenantProfiles(pageLink: PageLink, config?: RequestConfig): Observable<PageData<TenantProfile>> { |
|||
return this.http.get<PageData<TenantProfile>>(`/api/tenantProfiles${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getTenantProfile(tenantProfileId: string, config?: RequestConfig): Observable<TenantProfile> { |
|||
return this.http.get<TenantProfile>(`/api/tenantProfile/${tenantProfileId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public saveTenantProfile(tenantProfile: TenantProfile, config?: RequestConfig): Observable<TenantProfile> { |
|||
return this.http.post<TenantProfile>('/api/tenantProfile', tenantProfile, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public deleteTenantProfile(tenantProfileId: string, config?: RequestConfig) { |
|||
return this.http.delete(`/api/tenantProfile/${tenantProfileId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public setDefaultTenantProfile(tenantProfileId: string, config?: RequestConfig): Observable<TenantProfile> { |
|||
return this.http.post<TenantProfile>(`/api/tenantProfile/${tenantProfileId}/default`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getDefaultTenantProfileInfo(config?: RequestConfig): Observable<EntityInfoData> { |
|||
return this.http.get<EntityInfoData>('/api/tenantProfileInfo/default', defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getTenantProfileInfo(tenantProfileId: string, config?: RequestConfig): Observable<EntityInfoData> { |
|||
return this.http.get<EntityInfoData>(`/api/tenantProfileInfo/${tenantProfileId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getTenantProfileInfos(pageLink: PageLink, config?: RequestConfig): Observable<PageData<EntityInfoData>> { |
|||
return this.http.get<PageData<EntityInfoData>>(`/api/tenantProfileInfos${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2020 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<mat-form-field [formGroup]="selectTenantProfileFormGroup" class="mat-block"> |
|||
<input matInput type="text" placeholder="{{ 'tenant-profile.tenant-profile' | translate }}" |
|||
#tenantProfileInput |
|||
formControlName="tenantProfile" |
|||
[required]="required" |
|||
[matAutocomplete]="tenantProfileAutocomplete"> |
|||
<button *ngIf="selectTenantProfileFormGroup.get('tenantProfile').value && !disabled" |
|||
type="button" |
|||
matSuffix mat-button mat-icon-button aria-label="Clear" |
|||
(click)="clear()"> |
|||
<mat-icon class="material-icons">close</mat-icon> |
|||
</button> |
|||
<mat-autocomplete |
|||
class="tb-autocomplete" |
|||
#tenantProfileAutocomplete="matAutocomplete" |
|||
[displayWith]="displayTenantProfileFn"> |
|||
<mat-option *ngFor="let tenantProfile of filteredTenantProfiles | async" [value]="tenantProfile"> |
|||
<span [innerHTML]="tenantProfile.name | highlight:searchText"></span> |
|||
</mat-option> |
|||
<mat-option *ngIf="!(filteredTenantProfiles | async)?.length" [value]="null"> |
|||
<span> |
|||
{{ translate.get('tenant-profile.no-tenant-profiles-matching', {entity: searchText}) | async }} |
|||
</span> |
|||
</mat-option> |
|||
</mat-autocomplete> |
|||
<mat-error *ngIf="selectTenantProfileFormGroup.get('tenantProfile').hasError('required')"> |
|||
{{ 'tenant-profile.tenant-profile-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
@ -0,0 +1,171 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; |
|||
import { Observable } from 'rxjs'; |
|||
import { PageLink } from '@shared/models/page/page-link'; |
|||
import { Direction } from '@shared/models/page/sort-order'; |
|||
import { map, mergeMap, startWith, tap } from 'rxjs/operators'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@app/core/core.state'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { TenantProfileId } from '@shared/models/id/tenant-profile-id'; |
|||
import { EntityInfoData } from '@shared/models/entity.models'; |
|||
import { TenantProfileService } from '@core/http/tenant-profile.service'; |
|||
import { entityIdEquals } from '../../../../shared/models/id/entity-id'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-tenant-profile-autocomplete', |
|||
templateUrl: './tenant-profile-autocomplete.component.html', |
|||
styleUrls: [], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => TenantProfileAutocompleteComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class TenantProfileAutocompleteComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
selectTenantProfileFormGroup: FormGroup; |
|||
|
|||
modelValue: TenantProfileId | null; |
|||
|
|||
@Input() |
|||
selectDefaultProfile = false; |
|||
|
|||
private requiredValue: boolean; |
|||
get required(): boolean { |
|||
return this.requiredValue; |
|||
} |
|||
@Input() |
|||
set required(value: boolean) { |
|||
this.requiredValue = coerceBooleanProperty(value); |
|||
} |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
@ViewChild('tenantProfileInput', {static: true}) tenantProfileInput: ElementRef; |
|||
|
|||
filteredTenantProfiles: Observable<Array<EntityInfoData>>; |
|||
|
|||
searchText = ''; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private store: Store<AppState>, |
|||
public translate: TranslateService, |
|||
private tenantProfileService: TenantProfileService, |
|||
private fb: FormBuilder) { |
|||
this.selectTenantProfileFormGroup = this.fb.group({ |
|||
tenantProfile: [null] |
|||
}); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.filteredTenantProfiles = this.selectTenantProfileFormGroup.get('tenantProfile').valueChanges |
|||
.pipe( |
|||
tap((value: EntityInfoData | string) => { |
|||
let modelValue: TenantProfileId | null; |
|||
if (typeof value === 'string' || !value) { |
|||
modelValue = null; |
|||
} else { |
|||
modelValue = new TenantProfileId(value.id.id); |
|||
} |
|||
this.updateView(modelValue); |
|||
}), |
|||
startWith<string | EntityInfoData>(''), |
|||
map(value => value ? (typeof value === 'string' ? value : value.name) : ''), |
|||
mergeMap(name => this.fetchTenantProfiles(name) ) |
|||
); |
|||
} |
|||
|
|||
selectDefaultTenantProfileIfNeeded(): void { |
|||
if (this.selectDefaultProfile && !this.modelValue) { |
|||
this.tenantProfileService.getDefaultTenantProfileInfo().subscribe( |
|||
(profile) => { |
|||
if (profile) { |
|||
this.modelValue = new TenantProfileId(profile.id.id); |
|||
this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(profile, {emitEvent: false}); |
|||
this.propagateChange(this.modelValue); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
} |
|||
|
|||
writeValue(value: TenantProfileId | null): void { |
|||
this.searchText = ''; |
|||
if (value != null) { |
|||
this.tenantProfileService.getTenantProfileInfo(value.id).subscribe( |
|||
(profile) => { |
|||
this.modelValue = new TenantProfileId(profile.id.id); |
|||
this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(profile, {emitEvent: true}); |
|||
} |
|||
); |
|||
} else { |
|||
this.modelValue = null; |
|||
this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(null, {emitEvent: true}); |
|||
this.selectDefaultTenantProfileIfNeeded(); |
|||
} |
|||
} |
|||
|
|||
updateView(value: TenantProfileId | null) { |
|||
if (!entityIdEquals(this.modelValue, value)) { |
|||
this.modelValue = value; |
|||
this.propagateChange(this.modelValue); |
|||
} |
|||
} |
|||
|
|||
displayTenantProfileFn(profile?: EntityInfoData): string | undefined { |
|||
return profile ? profile.name : undefined; |
|||
} |
|||
|
|||
fetchTenantProfiles(searchText?: string): Observable<Array<EntityInfoData>> { |
|||
this.searchText = searchText; |
|||
const pageLink = new PageLink(10, 0, searchText, { |
|||
property: 'name', |
|||
direction: Direction.ASC |
|||
}); |
|||
return this.tenantProfileService.getTenantProfileInfos(pageLink, {ignoreLoading: true}).pipe( |
|||
map(pageData => { |
|||
return pageData.data; |
|||
}) |
|||
); |
|||
} |
|||
|
|||
clear() { |
|||
this.selectTenantProfileFormGroup.get('tenantProfile').patchValue(null, {emitEvent: true}); |
|||
setTimeout(() => { |
|||
this.tenantProfileInput.nativeElement.blur(); |
|||
this.tenantProfileInput.nativeElement.focus(); |
|||
}, 0); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2020 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<div class="tb-details-buttons" fxLayout.xs="column" *ngIf="!standalone"> |
|||
<button mat-raised-button color="primary" |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="onEntityAction($event, 'setDefault')" |
|||
[fxShow]="!isEdit && !entity?.default"> |
|||
{{'tenant-profile.set-default' | translate }} |
|||
</button> |
|||
<button mat-raised-button color="primary" |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="onEntityAction($event, 'delete')" |
|||
[fxShow]="!hideDelete() && !isEdit"> |
|||
{{'tenant-profile.delete' | translate }} |
|||
</button> |
|||
<div fxLayout="row" fxLayout.xs="column"> |
|||
<button mat-raised-button |
|||
ngxClipboard |
|||
(cbOnSuccess)="onTenantProfileIdCopied($event)" |
|||
[cbContent]="entity?.id?.id" |
|||
[fxShow]="!isEdit"> |
|||
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon> |
|||
<span translate>tenant-profile.copyId</span> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<div class="mat-padding" fxLayout="column"> |
|||
<form [formGroup]="entityForm"> |
|||
<fieldset [disabled]="(isLoading$ | async) || !isEdit"> |
|||
<mat-form-field class="mat-block"> |
|||
<mat-label translate>tenant-profile.name</mat-label> |
|||
<input matInput formControlName="name" required/> |
|||
<mat-error *ngIf="entityForm.get('name').hasError('required')"> |
|||
{{ 'tenant-profile.name-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<div fxLayout="column"> |
|||
<mat-checkbox class="hinted-checkbox" formControlName="isolatedTbCore"> |
|||
<div>{{ 'tenant.isolated-tb-core' | translate }}</div> |
|||
<div class="tb-hint">{{'tenant.isolated-tb-core-details' | translate}}</div> |
|||
</mat-checkbox> |
|||
<mat-checkbox class="hinted-checkbox" formControlName="isolatedTbRuleEngine"> |
|||
<div>{{ 'tenant.isolated-tb-rule-engine' | translate }}</div> |
|||
<div class="tb-hint">{{'tenant.isolated-tb-rule-engine-details' | translate}}</div> |
|||
</mat-checkbox> |
|||
</div> |
|||
<mat-form-field class="mat-block"> |
|||
<mat-label translate>tenant-profile.description</mat-label> |
|||
<textarea matInput formControlName="description" rows="2"></textarea> |
|||
</mat-form-field> |
|||
</fieldset> |
|||
</form> |
|||
</div> |
|||
@ -0,0 +1,96 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, Inject, Input } from '@angular/core'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { TenantProfile } from '@app/shared/models/tenant.model'; |
|||
import { ActionNotificationShow } from '@app/core/notification/notification.actions'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; |
|||
import { EntityComponent } from '../entity/entity.component'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-tenant-profile', |
|||
templateUrl: './tenant-profile.component.html', |
|||
styleUrls: ['./tenant-profile.component.scss'] |
|||
}) |
|||
export class TenantProfileComponent extends EntityComponent<TenantProfile> { |
|||
|
|||
@Input() |
|||
standalone = false; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
protected translate: TranslateService, |
|||
@Inject('entity') protected entityValue: TenantProfile, |
|||
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<TenantProfile>, |
|||
protected fb: FormBuilder) { |
|||
super(store, fb, entityValue, entitiesTableConfigValue); |
|||
} |
|||
|
|||
hideDelete() { |
|||
if (this.entitiesTableConfig) { |
|||
return !this.entitiesTableConfig.deleteEnabled(this.entity); |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
buildForm(entity: TenantProfile): FormGroup { |
|||
return this.fb.group( |
|||
{ |
|||
name: [entity ? entity.name : '', [Validators.required]], |
|||
isolatedTbCore: [entity ? entity.isolatedTbCore : false, []], |
|||
isolatedTbRuleEngine: [entity ? entity.isolatedTbRuleEngine : false, []], |
|||
description: [entity ? entity.description : '', []], |
|||
} |
|||
); |
|||
} |
|||
|
|||
updateForm(entity: TenantProfile) { |
|||
this.entityForm.patchValue({name: entity.name}); |
|||
this.entityForm.patchValue({isolatedTbCore: entity.isolatedTbCore}); |
|||
this.entityForm.patchValue({isolatedTbRuleEngine: entity.isolatedTbRuleEngine}); |
|||
this.entityForm.patchValue({description: entity.description}); |
|||
} |
|||
|
|||
updateFormState() { |
|||
if (this.entityForm) { |
|||
if (this.isEditValue) { |
|||
this.entityForm.enable({emitEvent: false}); |
|||
if (!this.isAdd) { |
|||
this.entityForm.get('isolatedTbCore').disable({emitEvent: false}); |
|||
this.entityForm.get('isolatedTbRuleEngine').disable({emitEvent: false}); |
|||
} |
|||
} else { |
|||
this.entityForm.disable({emitEvent: false}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
onTenantProfileIdCopied(event) { |
|||
this.store.dispatch(new ActionNotificationShow( |
|||
{ |
|||
message: this.translate.instant('tenant-profile.idCopiedMessage'), |
|||
type: 'success', |
|||
duration: 750, |
|||
verticalPosition: 'bottom', |
|||
horizontalPosition: 'right' |
|||
})); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
|
|||
import { EntitiesTableComponent } from '../../components/entity/entities-table.component'; |
|||
import { Authority } from '@shared/models/authority.enum'; |
|||
import { TenantProfilesTableConfigResolver } from './tenant-profiles-table-config.resolver'; |
|||
|
|||
const routes: Routes = [ |
|||
{ |
|||
path: 'tenantProfiles', |
|||
data: { |
|||
breadcrumb: { |
|||
label: 'tenant-profile.tenant-profiles', |
|||
icon: 'mdi:alpha-t-box' |
|||
} |
|||
}, |
|||
children: [ |
|||
{ |
|||
path: '', |
|||
component: EntitiesTableComponent, |
|||
data: { |
|||
auth: [Authority.SYS_ADMIN], |
|||
title: 'tenant-profile.tenant-profiles' |
|||
}, |
|||
resolve: { |
|||
entitiesTableConfig: TenantProfilesTableConfigResolver |
|||
} |
|||
} |
|||
] |
|||
} |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
providers: [ |
|||
TenantProfilesTableConfigResolver |
|||
] |
|||
}) |
|||
export class TenantProfileRoutingModule { } |
|||
@ -0,0 +1,43 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2020 The Thingsboard Authors |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
|||
|
|||
--> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab"> |
|||
<tb-attribute-table [defaultAttributeScope]="attributeScopes.SERVER_SCOPE" |
|||
[active]="attributesTab.isActive" |
|||
[entityId]="entity.id" |
|||
[entityName]="entity.name"> |
|||
</tb-attribute-table> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab"> |
|||
<tb-attribute-table [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY" |
|||
disableAttributeScopeSelection |
|||
[active]="telemetryTab.isActive" |
|||
[entityId]="entity.id" |
|||
[entityName]="entity.name"> |
|||
</tb-attribute-table> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'alarm.alarms' | translate }}" #alarmsTab="matTab"> |
|||
<tb-alarm-table [active]="alarmsTab.isActive" [entityId]="entity.id"></tb-alarm-table> |
|||
</mat-tab> |
|||
<mat-tab *ngIf="entity" |
|||
label="{{ 'tenant.events' | translate }}" #eventsTab="matTab"> |
|||
<tb-event-table [defaultEventType]="eventTypes.ERROR" [active]="eventsTab.isActive" [tenantId]="nullUid" |
|||
[entityId]="entity.id"></tb-event-table> |
|||
</mat-tab> |
|||
@ -0,0 +1,38 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; |
|||
import { TenantProfile } from '@shared/models/tenant.model'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-tenant-profile-tabs', |
|||
templateUrl: './tenant-profile-tabs.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class TenantProfileTabsComponent extends EntityTabsComponent<TenantProfile> { |
|||
|
|||
constructor(protected store: Store<AppState>) { |
|||
super(store); |
|||
} |
|||
|
|||
ngOnInit() { |
|||
super.ngOnInit(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { HomeComponentsModule } from '@modules/home/components/home-components.module'; |
|||
import { TenantProfileRoutingModule } from './tenant-profile-routing.module'; |
|||
import { TenantProfileTabsComponent } from './tenant-profile-tabs.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
TenantProfileTabsComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
HomeComponentsModule, |
|||
TenantProfileRoutingModule |
|||
] |
|||
}) |
|||
export class TenantProfileModule { } |
|||
@ -0,0 +1,122 @@ |
|||
///
|
|||
/// Copyright © 2016-2020 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { Resolve } from '@angular/router'; |
|||
import { TenantProfile } from '@shared/models/tenant.model'; |
|||
import { |
|||
checkBoxCell, |
|||
DateEntityTableColumn, |
|||
EntityTableColumn, |
|||
EntityTableConfig |
|||
} from '@home/models/entity/entities-table-config.models'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { DatePipe } from '@angular/common'; |
|||
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; |
|||
import { EntityAction } from '@home/models/entity/entity-component.models'; |
|||
import { TenantProfileService } from '@core/http/tenant-profile.service'; |
|||
import { TenantProfileComponent } from '../../components/profile/tenant-profile.component'; |
|||
import { TenantProfileTabsComponent } from './tenant-profile-tabs.component'; |
|||
import { DialogService } from '@core/services/dialog.service'; |
|||
|
|||
@Injectable() |
|||
export class TenantProfilesTableConfigResolver implements Resolve<EntityTableConfig<TenantProfile>> { |
|||
|
|||
private readonly config: EntityTableConfig<TenantProfile> = new EntityTableConfig<TenantProfile>(); |
|||
|
|||
constructor(private tenantProfileService: TenantProfileService, |
|||
private translate: TranslateService, |
|||
private datePipe: DatePipe, |
|||
private dialogService: DialogService) { |
|||
|
|||
this.config.entityType = EntityType.TENANT_PROFILE; |
|||
this.config.entityComponent = TenantProfileComponent; |
|||
this.config.entityTabsComponent = TenantProfileTabsComponent; |
|||
this.config.entityTranslations = entityTypeTranslations.get(EntityType.TENANT_PROFILE); |
|||
this.config.entityResources = entityTypeResources.get(EntityType.TENANT_PROFILE); |
|||
|
|||
this.config.columns.push( |
|||
new DateEntityTableColumn<TenantProfile>('createdTime', 'common.created-time', this.datePipe, '150px'), |
|||
new EntityTableColumn<TenantProfile>('name', 'tenant-profile.name', '40%'), |
|||
new EntityTableColumn<TenantProfile>('description', 'tenant-profile.description', '60%'), |
|||
new EntityTableColumn<TenantProfile>('isDefault', 'tenant-profile.default', '60px', |
|||
entity => { |
|||
return checkBoxCell(entity.default); |
|||
}) |
|||
); |
|||
|
|||
this.config.cellActionDescriptors.push( |
|||
{ |
|||
name: this.translate.instant('tenant-profile.set-default'), |
|||
icon: 'flag', |
|||
isEnabled: (tenantProfile) => !tenantProfile.default, |
|||
onAction: ($event, entity) => this.setDefaultTenantProfile($event, entity) |
|||
} |
|||
); |
|||
|
|||
this.config.deleteEntityTitle = tenantProfile => this.translate.instant('tenant-profile.delete-tenant-profile-title', |
|||
{ tenantProfileName: tenantProfile.name }); |
|||
this.config.deleteEntityContent = () => this.translate.instant('tenant-profile.delete-tenant-profile-text'); |
|||
this.config.deleteEntitiesTitle = count => this.translate.instant('tenant-profile.delete-tenant-profiles-title', {count}); |
|||
this.config.deleteEntitiesContent = () => this.translate.instant('tenant-profile.delete-tenant-profiles-text'); |
|||
|
|||
this.config.entitiesFetchFunction = pageLink => this.tenantProfileService.getTenantProfiles(pageLink); |
|||
this.config.loadEntity = id => this.tenantProfileService.getTenantProfile(id.id); |
|||
this.config.saveEntity = tenantProfile => this.tenantProfileService.saveTenantProfile(tenantProfile); |
|||
this.config.deleteEntity = id => this.tenantProfileService.deleteTenantProfile(id.id); |
|||
this.config.onEntityAction = action => this.onTenantProfileAction(action); |
|||
this.config.deleteEnabled = (tenantProfile) => tenantProfile && !tenantProfile.default; |
|||
this.config.entitySelectionEnabled = (tenantProfile) => tenantProfile && !tenantProfile.default; |
|||
} |
|||
|
|||
resolve(): EntityTableConfig<TenantProfile> { |
|||
this.config.tableTitle = this.translate.instant('tenant-profile.tenant-profiles'); |
|||
|
|||
return this.config; |
|||
} |
|||
|
|||
setDefaultTenantProfile($event: Event, tenantProfile: TenantProfile) { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
this.dialogService.confirm( |
|||
this.translate.instant('tenant-profile.set-default-tenant-profile-title', {tenantProfileName: tenantProfile.name}), |
|||
this.translate.instant('tenant-profile.set-default-tenant-profile-text'), |
|||
this.translate.instant('action.no'), |
|||
this.translate.instant('action.yes'), |
|||
true |
|||
).subscribe((res) => { |
|||
if (res) { |
|||
this.tenantProfileService.setDefaultTenantProfile(tenantProfile.id.id).subscribe( |
|||
() => { |
|||
this.config.table.updateData(); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
); |
|||
} |
|||
|
|||
onTenantProfileAction(action: EntityAction<TenantProfile>): boolean { |
|||
switch (action.action) { |
|||
case 'setDefault': |
|||
this.setDefaultTenantProfile(action.event, action.entity); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue