Devices page implementation
This commit is contained in:
parent
6c6d4fca83
commit
3700bcaa5d
@ -68,7 +68,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
|
|||||||
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
|
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
|
||||||
public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public";
|
public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public";
|
||||||
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
|
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
|
||||||
protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/static/**", "/api/noauth/**", "/webjars/**"};
|
protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**"};
|
||||||
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
|
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
|
||||||
public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**";
|
public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**";
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSecurity web) throws Exception {
|
public void configure(WebSecurity web) throws Exception {
|
||||||
web.ignoring().antMatchers("/static/**");
|
web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
@Controller
|
@Controller
|
||||||
public class WebConfig {
|
public class WebConfig {
|
||||||
|
|
||||||
@RequestMapping(value = "/{path:^(?!api$)(?!static$)(?!webjars$)[^\\.]*}/**")
|
@RequestMapping(value = "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)[^\\.]*}/**")
|
||||||
public String redirect() {
|
public String redirect() {
|
||||||
return "forward:/index.html";
|
return "forward:/index.html";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,9 +31,9 @@ export class CustomerService {
|
|||||||
private http: HttpClient
|
private http: HttpClient
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
public getCustomers(tenantId: string, pageLink: PageLink, ignoreErrors: boolean = false,
|
public getCustomers(pageLink: PageLink, ignoreErrors: boolean = false,
|
||||||
ignoreLoading: boolean = false): Observable<PageData<Customer>> {
|
ignoreLoading: boolean = false): Observable<PageData<Customer>> {
|
||||||
return this.http.get<PageData<Customer>>(`/api/tenant/${tenantId}/customers${pageLink.toQuery()}`,
|
return this.http.get<PageData<Customer>>(`/api/customers${pageLink.toQuery()}`,
|
||||||
defaultHttpOptions(ignoreLoading, ignoreErrors));
|
defaultHttpOptions(ignoreLoading, ignoreErrors));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,15 +16,16 @@
|
|||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { defaultHttpOptions } from './http-utils';
|
import { defaultHttpOptions } from './http-utils';
|
||||||
import { Observable } from 'rxjs/index';
|
import { Observable, Subject, ReplaySubject } from 'rxjs/index';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { PageLink } from '@shared/models/page/page-link';
|
import { PageLink } from '@shared/models/page/page-link';
|
||||||
import { PageData } from '@shared/models/page/page-data';
|
import { PageData } from '@shared/models/page/page-data';
|
||||||
import { Tenant } from '@shared/models/tenant.model';
|
import { Tenant } from '@shared/models/tenant.model';
|
||||||
import {DashboardInfo, Dashboard} from '@shared/models/dashboard.models';
|
import {DashboardInfo, Dashboard} from '@shared/models/dashboard.models';
|
||||||
import {map} from 'rxjs/operators';
|
import {map} from 'rxjs/operators';
|
||||||
import {DeviceInfo, Device} from '@app/shared/models/device.models';
|
import {DeviceInfo, Device, DeviceCredentials} from '@app/shared/models/device.models';
|
||||||
import {EntitySubtype} from '@app/shared/models/entity-type.models';
|
import {EntitySubtype} from '@app/shared/models/entity-type.models';
|
||||||
|
import {AuthService} from '../auth/auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -67,6 +68,40 @@ export class DeviceService {
|
|||||||
return this.http.get<Array<EntitySubtype>>('/api/device/types', defaultHttpOptions(ignoreLoading, ignoreErrors));
|
return this.http.get<Array<EntitySubtype>>('/api/device/types', defaultHttpOptions(ignoreLoading, ignoreErrors));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getDeviceCredentials(deviceId: string, sync: boolean = false, ignoreErrors: boolean = false,
|
||||||
|
ignoreLoading: boolean = false): Observable<DeviceCredentials> {
|
||||||
|
const url = `/api/device/${deviceId}/credentials`;
|
||||||
|
if (sync) {
|
||||||
|
const responseSubject = new ReplaySubject<DeviceCredentials>();
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
request.open('GET', url, false);
|
||||||
|
request.setRequestHeader('Accept', 'application/json, text/plain, */*');
|
||||||
|
const jwtToken = AuthService.getJwtToken();
|
||||||
|
if (jwtToken) {
|
||||||
|
request.setRequestHeader('X-Authorization', 'Bearer ' + jwtToken);
|
||||||
|
}
|
||||||
|
request.send(null);
|
||||||
|
if (request.status === 200) {
|
||||||
|
const credentials = JSON.parse(request.responseText) as DeviceCredentials;
|
||||||
|
responseSubject.next(credentials);
|
||||||
|
} else {
|
||||||
|
responseSubject.error(null);
|
||||||
|
}
|
||||||
|
return responseSubject.asObservable();
|
||||||
|
} else {
|
||||||
|
return this.http.get<DeviceCredentials>(url, defaultHttpOptions(ignoreLoading, ignoreErrors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public saveDeviceCredentials(deviceCredentials: DeviceCredentials, ignoreErrors: boolean = false,
|
||||||
|
ignoreLoading: boolean = false): Observable<DeviceCredentials> {
|
||||||
|
return this.http.post<DeviceCredentials>('/api/device/credentials', deviceCredentials, defaultHttpOptions(ignoreLoading, ignoreErrors));
|
||||||
|
}
|
||||||
|
|
||||||
|
public makeDevicePublic(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Device> {
|
||||||
|
return this.http.post<Device>(`/api/customer/public/device/${deviceId}`, null, defaultHttpOptions(ignoreLoading, ignoreErrors));
|
||||||
|
}
|
||||||
|
|
||||||
public unassignDeviceFromCustomer(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) {
|
public unassignDeviceFromCustomer(deviceId: string, ignoreErrors: boolean = false, ignoreLoading: boolean = false) {
|
||||||
return this.http.delete(`/api/customer/device/${deviceId}`, defaultHttpOptions(ignoreLoading, ignoreErrors));
|
return this.http.delete(`/api/customer/device/${deviceId}`, defaultHttpOptions(ignoreLoading, ignoreErrors));
|
||||||
}
|
}
|
||||||
|
|||||||
263
ui-ngx/src/app/core/http/entity.service.ts
Normal file
263
ui-ngx/src/app/core/http/entity.service.ts
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {Observable, throwError, of, empty, EMPTY} from 'rxjs/index';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {PageLink} from '@shared/models/page/page-link';
|
||||||
|
import {EntityType} from '@shared/models/entity-type.models';
|
||||||
|
import {BaseData} from '@shared/models/base-data';
|
||||||
|
import {EntityId} from '@shared/models/id/entity-id';
|
||||||
|
import {DeviceService} from '@core/http/device.service';
|
||||||
|
import {TenantService} from '@core/http/tenant.service';
|
||||||
|
import {CustomerService} from '@core/http/customer.service';
|
||||||
|
import {UserService} from './user.service';
|
||||||
|
import {DashboardService} from '@core/http/dashboard.service';
|
||||||
|
import {Direction} from '@shared/models/page/sort-order';
|
||||||
|
import {PageData} from '@shared/models/page/page-data';
|
||||||
|
import {getCurrentAuthUser} from '../auth/auth.selectors';
|
||||||
|
import {Store} from '@ngrx/store';
|
||||||
|
import {AppState} from '@core/core.state';
|
||||||
|
import {Authority} from '@shared/models/authority.enum';
|
||||||
|
import {Tenant} from '@shared/models/tenant.model';
|
||||||
|
import {concatMap, expand, map, toArray} from 'rxjs/operators';
|
||||||
|
import {Customer} from '@app/shared/models/customer.model';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class EntityService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
private store: Store<AppState>,
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
private tenantService: TenantService,
|
||||||
|
private customerService: CustomerService,
|
||||||
|
private userService: UserService,
|
||||||
|
private dashboardService: DashboardService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
private getEntityObservable(entityType: EntityType, entityId: string,
|
||||||
|
ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<BaseData<EntityId>> {
|
||||||
|
|
||||||
|
let observable: Observable<BaseData<EntityId>>;
|
||||||
|
switch (entityType) {
|
||||||
|
case EntityType.DEVICE:
|
||||||
|
observable = this.deviceService.getDevice(entityId, ignoreErrors, ignoreLoading);
|
||||||
|
break;
|
||||||
|
case EntityType.ASSET:
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
case EntityType.ENTITY_VIEW:
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
case EntityType.TENANT:
|
||||||
|
observable = this.tenantService.getTenant(entityId, ignoreErrors, ignoreLoading);
|
||||||
|
break;
|
||||||
|
case EntityType.CUSTOMER:
|
||||||
|
observable = this.customerService.getCustomer(entityId, ignoreErrors, ignoreLoading);
|
||||||
|
break;
|
||||||
|
case EntityType.DASHBOARD:
|
||||||
|
observable = this.dashboardService.getDashboardInfo(entityId, ignoreErrors, ignoreLoading);
|
||||||
|
break;
|
||||||
|
case EntityType.USER:
|
||||||
|
observable = this.userService.getUser(entityId, ignoreErrors, ignoreLoading);
|
||||||
|
break;
|
||||||
|
case EntityType.RULE_CHAIN:
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
case EntityType.ALARM:
|
||||||
|
console.error('Get Alarm Entity is not implemented!');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return observable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEntity(entityType: EntityType, entityId: string,
|
||||||
|
ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<BaseData<EntityId>> {
|
||||||
|
const entityObservable = this.getEntityObservable(entityType, entityId, ignoreErrors, ignoreLoading);
|
||||||
|
if (entityObservable) {
|
||||||
|
return entityObservable;
|
||||||
|
} else {
|
||||||
|
return throwError(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSingleTenantByPageLinkObservable(pageLink: PageLink,
|
||||||
|
ignoreErrors: boolean = false,
|
||||||
|
ignoreLoading: boolean = false): Observable<PageData<Tenant>> {
|
||||||
|
const authUser = getCurrentAuthUser(this.store);
|
||||||
|
const tenantId = authUser.tenantId;
|
||||||
|
return this.tenantService.getTenant(tenantId, ignoreErrors, ignoreLoading).pipe(
|
||||||
|
map((tenant) => {
|
||||||
|
const result = {
|
||||||
|
data: [],
|
||||||
|
totalPages: 0,
|
||||||
|
totalElements: 0,
|
||||||
|
hasNext: false
|
||||||
|
} as PageData<Tenant>;
|
||||||
|
if (tenant.title.toLowerCase().startsWith(pageLink.textSearch.toLowerCase())) {
|
||||||
|
result.data.push(tenant);
|
||||||
|
result.totalPages = 1;
|
||||||
|
result.totalElements = 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSingleCustomerByPageLinkObservable(pageLink: PageLink,
|
||||||
|
ignoreErrors: boolean = false,
|
||||||
|
ignoreLoading: boolean = false): Observable<PageData<Customer>> {
|
||||||
|
const authUser = getCurrentAuthUser(this.store);
|
||||||
|
const customerId = authUser.customerId;
|
||||||
|
return this.customerService.getCustomer(customerId, ignoreErrors, ignoreLoading).pipe(
|
||||||
|
map((customer) => {
|
||||||
|
const result = {
|
||||||
|
data: [],
|
||||||
|
totalPages: 0,
|
||||||
|
totalElements: 0,
|
||||||
|
hasNext: false
|
||||||
|
} as PageData<Customer>;
|
||||||
|
if (customer.title.toLowerCase().startsWith(pageLink.textSearch.toLowerCase())) {
|
||||||
|
result.data.push(customer);
|
||||||
|
result.totalPages = 1;
|
||||||
|
result.totalElements = 1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEntitiesByPageLinkObservable(entityType: EntityType, pageLink: PageLink, subType: string = '',
|
||||||
|
ignoreErrors: boolean = false,
|
||||||
|
ignoreLoading: boolean = false): Observable<PageData<BaseData<EntityId>>> {
|
||||||
|
let entitiesObservable: Observable<PageData<BaseData<EntityId>>>;
|
||||||
|
const authUser = getCurrentAuthUser(this.store);
|
||||||
|
const customerId = authUser.customerId;
|
||||||
|
switch (entityType) {
|
||||||
|
case EntityType.DEVICE:
|
||||||
|
pageLink.sortOrder.property = 'name';
|
||||||
|
if (authUser.authority === Authority.CUSTOMER_USER) {
|
||||||
|
entitiesObservable = this.deviceService.getCustomerDeviceInfos(customerId, pageLink, subType, ignoreErrors, ignoreLoading);
|
||||||
|
} else {
|
||||||
|
entitiesObservable = this.deviceService.getTenantDeviceInfos(pageLink, subType, ignoreErrors, ignoreLoading);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntityType.ASSET:
|
||||||
|
pageLink.sortOrder.property = 'name';
|
||||||
|
if (authUser.authority === Authority.CUSTOMER_USER) {
|
||||||
|
// TODO:
|
||||||
|
} else {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntityType.ENTITY_VIEW:
|
||||||
|
pageLink.sortOrder.property = 'name';
|
||||||
|
if (authUser.authority === Authority.CUSTOMER_USER) {
|
||||||
|
// TODO:
|
||||||
|
} else {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntityType.TENANT:
|
||||||
|
pageLink.sortOrder.property = 'title';
|
||||||
|
if (authUser.authority === Authority.TENANT_ADMIN) {
|
||||||
|
entitiesObservable = this.getSingleTenantByPageLinkObservable(pageLink, ignoreErrors, ignoreLoading);
|
||||||
|
} else {
|
||||||
|
entitiesObservable = this.tenantService.getTenants(pageLink, ignoreErrors, ignoreLoading);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntityType.CUSTOMER:
|
||||||
|
pageLink.sortOrder.property = 'title';
|
||||||
|
if (authUser.authority === Authority.CUSTOMER_USER) {
|
||||||
|
entitiesObservable = this.getSingleCustomerByPageLinkObservable(pageLink, ignoreErrors, ignoreLoading);
|
||||||
|
} else {
|
||||||
|
entitiesObservable = this.customerService.getCustomers(pageLink, ignoreErrors, ignoreLoading);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntityType.RULE_CHAIN:
|
||||||
|
pageLink.sortOrder.property = 'name';
|
||||||
|
// TODO:
|
||||||
|
break;
|
||||||
|
case EntityType.DASHBOARD:
|
||||||
|
pageLink.sortOrder.property = 'title';
|
||||||
|
if (authUser.authority === Authority.CUSTOMER_USER) {
|
||||||
|
entitiesObservable = this.dashboardService.getCustomerDashboards(customerId, pageLink, ignoreErrors, ignoreLoading);
|
||||||
|
} else {
|
||||||
|
entitiesObservable = this.dashboardService.getTenantDashboards(pageLink, ignoreErrors, ignoreLoading);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EntityType.USER:
|
||||||
|
console.error('Get User Entities is not implemented!');
|
||||||
|
break;
|
||||||
|
case EntityType.ALARM:
|
||||||
|
console.error('Get Alarm Entities is not implemented!');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return entitiesObservable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEntitiesByPageLink(entityType: EntityType, pageLink: PageLink, subType: string = '',
|
||||||
|
ignoreErrors: boolean = false,
|
||||||
|
ignoreLoading: boolean = false): Observable<Array<BaseData<EntityId>>> {
|
||||||
|
const entitiesObservable: Observable<PageData<BaseData<EntityId>>> =
|
||||||
|
this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, ignoreErrors, ignoreLoading);
|
||||||
|
if (entitiesObservable) {
|
||||||
|
return entitiesObservable.pipe(
|
||||||
|
expand((data) => {
|
||||||
|
if (data.hasNext) {
|
||||||
|
pageLink.page += 1;
|
||||||
|
return this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, ignoreErrors, ignoreLoading);
|
||||||
|
} else {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
map((data) => data.data),
|
||||||
|
concatMap((data) => data),
|
||||||
|
toArray()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return of(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEntitiesByNameFilter(entityType: EntityType, entityNameFilter: string,
|
||||||
|
pageSize: number, subType: string = '',
|
||||||
|
ignoreErrors: boolean = false, ignoreLoading: boolean = false): Observable<Array<BaseData<EntityId>>> {
|
||||||
|
const pageLink = new PageLink(pageSize, 0, entityNameFilter, {
|
||||||
|
property: 'name',
|
||||||
|
direction: Direction.ASC
|
||||||
|
});
|
||||||
|
if (pageSize === -1) { // all
|
||||||
|
pageLink.pageSize = 100;
|
||||||
|
return this.getEntitiesByPageLink(entityType, pageLink, subType, ignoreErrors, ignoreLoading).pipe(
|
||||||
|
map((data) => data && data.length ? data : null)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const entitiesObservable: Observable<PageData<BaseData<EntityId>>> =
|
||||||
|
this.getEntitiesByPageLinkObservable(entityType, pageLink, subType, ignoreErrors, ignoreLoading);
|
||||||
|
if (entitiesObservable) {
|
||||||
|
return entitiesObservable.pipe(
|
||||||
|
map((data) => data && data.data.length ? data.data : null)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return of(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright © 2016-2019 The Thingsboard Authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<form #deviceCredentialsForm="ngForm" [formGroup]="deviceCredentialsFormGroup" (ngSubmit)="save()">
|
||||||
|
<mat-toolbar fxLayout="row" color="primary">
|
||||||
|
<h2 translate>device.device-credentials</h2>
|
||||||
|
<span fxFlex></span>
|
||||||
|
<button mat-button mat-icon-button
|
||||||
|
(click)="cancel()"
|
||||||
|
type="button">
|
||||||
|
<mat-icon class="material-icons">close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-toolbar>
|
||||||
|
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
|
||||||
|
</mat-progress-bar>
|
||||||
|
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<fieldset [disabled]="(isLoading$ | async) || isReadOnly">
|
||||||
|
<mat-form-field class="mat-block">
|
||||||
|
<mat-label translate>device.credentials-type</mat-label>
|
||||||
|
<mat-select matInput formControlName="credentialsType"
|
||||||
|
(ngModelChange)="credentialsTypeChanged()">
|
||||||
|
<mat-option *ngFor="let credentialsType of credentialsTypes" [value]="credentialsType">
|
||||||
|
{{ credentialTypeNamesMap.get(credentialsType) }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field *ngIf="deviceCredentialsFormGroup.get('credentialsType').value === deviceCredentialsType.ACCESS_TOKEN"
|
||||||
|
class="mat-block">
|
||||||
|
<mat-label translate>device.access-token</mat-label>
|
||||||
|
<input matInput formControlName="credentialsId" required>
|
||||||
|
<mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsId').hasError('required')">
|
||||||
|
{{ 'device.access-token-required' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
<mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsId').hasError('pattern')">
|
||||||
|
{{ 'device.access-token-invalid' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field *ngIf="deviceCredentialsFormGroup.get('credentialsType').value === deviceCredentialsType.X509_CERTIFICATE"
|
||||||
|
class="mat-block">
|
||||||
|
<mat-label translate>device.rsa-key</mat-label>
|
||||||
|
<textarea matInput formControlName="credentialsValue" cols="15" rows="5" required></textarea>
|
||||||
|
<mat-error *ngIf="deviceCredentialsFormGroup.get('credentialsValue').hasError('required')">
|
||||||
|
{{ 'device.rsa-key-required' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions fxLayout="row">
|
||||||
|
<span fxFlex></span>
|
||||||
|
<button *ngIf="!isReadOnly" mat-button mat-raised-button color="primary"
|
||||||
|
type="submit"
|
||||||
|
[disabled]="(isLoading$ | async) || deviceCredentialsForm.invalid
|
||||||
|
|| !deviceCredentialsForm.dirty">
|
||||||
|
{{ 'action.save' | translate }}
|
||||||
|
</button>
|
||||||
|
<button mat-button color="primary"
|
||||||
|
style="margin-right: 20px;"
|
||||||
|
type="button"
|
||||||
|
[disabled]="(isLoading$ | async)"
|
||||||
|
(click)="cancel()" cdkFocusInitial>
|
||||||
|
{{ (isReadOnly ? 'action.close' : 'action.cancel') | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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, OnInit, SkipSelf, Inject} from '@angular/core';
|
||||||
|
import {ErrorStateMatcher, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material';
|
||||||
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '@core/core.state';
|
||||||
|
import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms';
|
||||||
|
import { ActionNotificationShow } from '@core/notification/notification.actions';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { AuthService } from '@core/auth/auth.service';
|
||||||
|
import {DeviceService} from '@core/http/device.service';
|
||||||
|
import {DeviceCredentials, DeviceCredentialsType, credentialTypeNames} from '@shared/models/device.models';
|
||||||
|
|
||||||
|
export interface DeviceCredentialsDialogData {
|
||||||
|
isReadOnly: boolean;
|
||||||
|
deviceId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-device-credentials-dialog',
|
||||||
|
templateUrl: './device-credentials-dialog.component.html',
|
||||||
|
providers: [{provide: ErrorStateMatcher, useExisting: DeviceCredentialsDialogComponent}],
|
||||||
|
styleUrls: []
|
||||||
|
})
|
||||||
|
export class DeviceCredentialsDialogComponent extends PageComponent implements OnInit, ErrorStateMatcher {
|
||||||
|
|
||||||
|
deviceCredentialsFormGroup: FormGroup;
|
||||||
|
|
||||||
|
isReadOnly: boolean;
|
||||||
|
|
||||||
|
deviceCredentials: DeviceCredentials;
|
||||||
|
|
||||||
|
submitted = false;
|
||||||
|
|
||||||
|
deviceCredentialsType = DeviceCredentialsType;
|
||||||
|
|
||||||
|
credentialsTypes = Object.keys(DeviceCredentialsType);
|
||||||
|
|
||||||
|
credentialTypeNamesMap = credentialTypeNames;
|
||||||
|
|
||||||
|
constructor(protected store: Store<AppState>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: DeviceCredentialsDialogData,
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
|
||||||
|
public dialogRef: MatDialogRef<DeviceCredentialsDialogComponent, DeviceCredentials>,
|
||||||
|
public fb: FormBuilder) {
|
||||||
|
super(store);
|
||||||
|
|
||||||
|
this.isReadOnly = data.isReadOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.deviceCredentialsFormGroup = this.fb.group({
|
||||||
|
credentialsType: [DeviceCredentialsType.ACCESS_TOKEN],
|
||||||
|
credentialsId: [''],
|
||||||
|
credentialsValue: ['']
|
||||||
|
});
|
||||||
|
if (this.isReadOnly) {
|
||||||
|
this.deviceCredentialsFormGroup.disable({emitEvent: false});
|
||||||
|
} else {
|
||||||
|
this.registerDisableOnLoadFormControl(this.deviceCredentialsFormGroup.get('credentialsType'));
|
||||||
|
}
|
||||||
|
this.loadDeviceCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||||
|
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
|
||||||
|
const customErrorState = !!(control && control.invalid && this.submitted);
|
||||||
|
return originalErrorState || customErrorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDeviceCredentials() {
|
||||||
|
this.deviceService.getDeviceCredentials(this.data.deviceId).subscribe(
|
||||||
|
(deviceCredentials) => {
|
||||||
|
this.deviceCredentials = deviceCredentials;
|
||||||
|
this.deviceCredentialsFormGroup.patchValue({
|
||||||
|
credentialsType: deviceCredentials.credentialsType,
|
||||||
|
credentialsId: deviceCredentials.credentialsId,
|
||||||
|
credentialsValue: deviceCredentials.credentialsValue
|
||||||
|
});
|
||||||
|
this.updateValidators();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
credentialsTypeChanged(): void {
|
||||||
|
this.deviceCredentialsFormGroup.patchValue(
|
||||||
|
{credentialsId: null, credentialsValue: null}, {emitEvent: true});
|
||||||
|
this.updateValidators();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateValidators(): void {
|
||||||
|
const crendetialsType = this.deviceCredentialsFormGroup.get('credentialsType').value as DeviceCredentialsType;
|
||||||
|
switch (crendetialsType) {
|
||||||
|
case DeviceCredentialsType.ACCESS_TOKEN:
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsId').setValidators([Validators.max(20), Validators.pattern(/^.{1,20}$/)]);
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity();
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([]);
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity();
|
||||||
|
break;
|
||||||
|
case DeviceCredentialsType.X509_CERTIFICATE:
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsValue').setValidators([Validators.required]);
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsValue').updateValueAndValidity();
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsId').setValidators([]);
|
||||||
|
this.deviceCredentialsFormGroup.get('credentialsId').updateValueAndValidity();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel(): void {
|
||||||
|
this.dialogRef.close(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
save(): void {
|
||||||
|
this.submitted = true;
|
||||||
|
this.deviceCredentials = {...this.deviceCredentials, ...this.deviceCredentialsFormGroup.value};
|
||||||
|
this.deviceService.saveDeviceCredentials(this.deviceCredentials).subscribe(
|
||||||
|
(deviceCredentials) => {
|
||||||
|
this.dialogRef.close(deviceCredentials);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,6 +26,10 @@ import { Authority } from '@shared/models/authority.enum';
|
|||||||
import {DeviceInfo} from '@shared/models/device.models';
|
import {DeviceInfo} from '@shared/models/device.models';
|
||||||
import {EntityType} from '@shared/models/entity-type.models';
|
import {EntityType} from '@shared/models/entity-type.models';
|
||||||
import {NULL_UUID} from '@shared/models/id/has-uuid';
|
import {NULL_UUID} from '@shared/models/id/has-uuid';
|
||||||
|
import {ActionNotificationShow} from '@core/notification/notification.actions';
|
||||||
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
|
import {DeviceService} from '@core/http/device.service';
|
||||||
|
import {ClipboardService} from 'ngx-clipboard';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-device',
|
selector: 'tb-device',
|
||||||
@ -39,6 +43,9 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
|
|||||||
deviceScope: 'tenant' | 'customer' | 'customer_user';
|
deviceScope: 'tenant' | 'customer' | 'customer_user';
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
|
protected translate: TranslateService,
|
||||||
|
private deviceService: DeviceService,
|
||||||
|
private clipboardService: ClipboardService,
|
||||||
public fb: FormBuilder) {
|
public fb: FormBuilder) {
|
||||||
super(store);
|
super(store);
|
||||||
}
|
}
|
||||||
@ -85,4 +92,35 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
|
|||||||
this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
|
this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onDeviceIdCopied($event) {
|
||||||
|
this.store.dispatch(new ActionNotificationShow(
|
||||||
|
{
|
||||||
|
message: this.translate.instant('device.idCopiedMessage'),
|
||||||
|
type: 'success',
|
||||||
|
duration: 750,
|
||||||
|
verticalPosition: 'bottom',
|
||||||
|
horizontalPosition: 'right'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
copyAccessToken($event) {
|
||||||
|
if (this.entity.id) {
|
||||||
|
this.deviceService.getDeviceCredentials(this.entity.id.id, true).subscribe(
|
||||||
|
(deviceCredentials) => {
|
||||||
|
const credentialsId = deviceCredentials.credentialsId;
|
||||||
|
if (this.clipboardService.copyFromContent(credentialsId)) {
|
||||||
|
this.store.dispatch(new ActionNotificationShow(
|
||||||
|
{
|
||||||
|
message: this.translate.instant('device.accessTokenCopiedMessage'),
|
||||||
|
type: 'success',
|
||||||
|
duration: 750,
|
||||||
|
verticalPosition: 'bottom',
|
||||||
|
horizontalPosition: 'right'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,15 +20,18 @@ import { SharedModule } from '@shared/shared.module';
|
|||||||
import {DeviceComponent} from '@modules/home/pages/device/device.component';
|
import {DeviceComponent} from '@modules/home/pages/device/device.component';
|
||||||
import {DeviceRoutingModule} from './device-routing.module';
|
import {DeviceRoutingModule} from './device-routing.module';
|
||||||
import {DeviceTableHeaderComponent} from '@modules/home/pages/device/device-table-header.component';
|
import {DeviceTableHeaderComponent} from '@modules/home/pages/device/device-table-header.component';
|
||||||
|
import {DeviceCredentialsDialogComponent} from '@modules/home/pages/device/device-credentials-dialog.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
DeviceComponent,
|
DeviceComponent,
|
||||||
DeviceTableHeaderComponent
|
DeviceTableHeaderComponent,
|
||||||
|
DeviceCredentialsDialogComponent
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
DeviceComponent,
|
DeviceComponent,
|
||||||
DeviceTableHeaderComponent
|
DeviceTableHeaderComponent,
|
||||||
|
DeviceCredentialsDialogComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
|||||||
@ -24,7 +24,8 @@ import {
|
|||||||
checkBoxCell,
|
checkBoxCell,
|
||||||
DateEntityTableColumn,
|
DateEntityTableColumn,
|
||||||
EntityTableColumn,
|
EntityTableColumn,
|
||||||
EntityTableConfig
|
EntityTableConfig,
|
||||||
|
HeaderActionDescriptor
|
||||||
} from '@shared/components/entity/entities-table-config.models';
|
} from '@shared/components/entity/entities-table-config.models';
|
||||||
import { TenantService } from '@core/http/tenant.service';
|
import { TenantService } from '@core/http/tenant.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@ -37,7 +38,7 @@ import {
|
|||||||
import { TenantComponent } from '@modules/home/pages/tenant/tenant.component';
|
import { TenantComponent } from '@modules/home/pages/tenant/tenant.component';
|
||||||
import { EntityAction } from '@shared/components/entity/entity-component.models';
|
import { EntityAction } from '@shared/components/entity/entity-component.models';
|
||||||
import { User } from '@shared/models/user.model';
|
import { User } from '@shared/models/user.model';
|
||||||
import {Device, DeviceInfo} from '@app/shared/models/device.models';
|
import {Device, DeviceCredentials, DeviceInfo} from '@app/shared/models/device.models';
|
||||||
import {DeviceComponent} from '@modules/home/pages/device/device.component';
|
import {DeviceComponent} from '@modules/home/pages/device/device.component';
|
||||||
import {Observable, of} from 'rxjs';
|
import {Observable, of} from 'rxjs';
|
||||||
import {select, Store} from '@ngrx/store';
|
import {select, Store} from '@ngrx/store';
|
||||||
@ -51,6 +52,12 @@ import {Customer} from '@app/shared/models/customer.model';
|
|||||||
import {NULL_UUID} from '@shared/models/id/has-uuid';
|
import {NULL_UUID} from '@shared/models/id/has-uuid';
|
||||||
import {BroadcastService} from '@core/services/broadcast.service';
|
import {BroadcastService} from '@core/services/broadcast.service';
|
||||||
import {DeviceTableHeaderComponent} from '@modules/home/pages/device/device-table-header.component';
|
import {DeviceTableHeaderComponent} from '@modules/home/pages/device/device-table-header.component';
|
||||||
|
import {MatDialog} from '@angular/material';
|
||||||
|
import {
|
||||||
|
DeviceCredentialsDialogComponent,
|
||||||
|
DeviceCredentialsDialogData
|
||||||
|
} from '@modules/home/pages/device/device-credentials-dialog.component';
|
||||||
|
import {DialogService} from '@core/services/dialog.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> {
|
export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<DeviceInfo>> {
|
||||||
@ -63,9 +70,11 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
|
|||||||
private broadcast: BroadcastService,
|
private broadcast: BroadcastService,
|
||||||
private deviceService: DeviceService,
|
private deviceService: DeviceService,
|
||||||
private customerService: CustomerService,
|
private customerService: CustomerService,
|
||||||
|
private dialogService: DialogService,
|
||||||
private translate: TranslateService,
|
private translate: TranslateService,
|
||||||
private datePipe: DatePipe,
|
private datePipe: DatePipe,
|
||||||
private router: Router) {
|
private router: Router,
|
||||||
|
private dialog: MatDialog) {
|
||||||
|
|
||||||
this.config.entityType = EntityType.CUSTOMER;
|
this.config.entityType = EntityType.CUSTOMER;
|
||||||
this.config.entityComponent = DeviceComponent;
|
this.config.entityComponent = DeviceComponent;
|
||||||
@ -122,6 +131,7 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
|
|||||||
this.config.columns = this.configureColumns(this.config.componentsData.deviceScope);
|
this.config.columns = this.configureColumns(this.config.componentsData.deviceScope);
|
||||||
this.configureEntityFunctions(this.config.componentsData.deviceScope);
|
this.configureEntityFunctions(this.config.componentsData.deviceScope);
|
||||||
this.config.cellActionDescriptors = this.configureCellActions(this.config.componentsData.deviceScope);
|
this.config.cellActionDescriptors = this.configureCellActions(this.config.componentsData.deviceScope);
|
||||||
|
this.config.addActionDescriptors = this.configureAddActions(this.config.componentsData.deviceScope);
|
||||||
return this.config;
|
return this.config;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -154,16 +164,18 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
|
|||||||
|
|
||||||
configureEntityFunctions(deviceScope: string): void {
|
configureEntityFunctions(deviceScope: string): void {
|
||||||
if (deviceScope === 'tenant') {
|
if (deviceScope === 'tenant') {
|
||||||
this.config.entitiesFetchFunction = pageLink => this.deviceService.getTenantDeviceInfos(pageLink, this.config.componentsData.deviceType);
|
this.config.entitiesFetchFunction = pageLink =>
|
||||||
|
this.deviceService.getTenantDeviceInfos(pageLink, this.config.componentsData.deviceType);
|
||||||
this.config.deleteEntity = id => this.deviceService.deleteDevice(id.id);
|
this.config.deleteEntity = id => this.deviceService.deleteDevice(id.id);
|
||||||
} else {
|
} else {
|
||||||
this.config.entitiesFetchFunction = pageLink => this.deviceService.getCustomerDeviceInfos(this.customerId, pageLink, this.config.componentsData.deviceType);
|
this.config.entitiesFetchFunction = pageLink =>
|
||||||
|
this.deviceService.getCustomerDeviceInfos(this.customerId, pageLink, this.config.componentsData.deviceType);
|
||||||
this.config.deleteEntity = id => this.deviceService.unassignDeviceFromCustomer(id.id);
|
this.config.deleteEntity = id => this.deviceService.unassignDeviceFromCustomer(id.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configureCellActions(deviceScope: string): Array<CellActionDescriptor<Device | DeviceInfo>> {
|
configureCellActions(deviceScope: string): Array<CellActionDescriptor<DeviceInfo>> {
|
||||||
const actions: Array<CellActionDescriptor<Device | DeviceInfo>> = [];
|
const actions: Array<CellActionDescriptor<Device>> = [];
|
||||||
if (deviceScope === 'tenant') {
|
if (deviceScope === 'tenant') {
|
||||||
actions.push(
|
actions.push(
|
||||||
{
|
{
|
||||||
@ -177,18 +189,122 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
makePublic($event: Event, device: Device) {
|
configureAddActions(deviceScope: string): Array<HeaderActionDescriptor> {
|
||||||
|
const actions: Array<HeaderActionDescriptor> = [];
|
||||||
|
actions.push(
|
||||||
|
{
|
||||||
|
name: this.translate.instant('device.add-device-text'),
|
||||||
|
icon: 'insert_drive_file',
|
||||||
|
isEnabled: () => true,
|
||||||
|
onAction: ($event) => this.config.table.addEntity($event)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.translate.instant('device.import'),
|
||||||
|
icon: 'file_upload',
|
||||||
|
isEnabled: () => true,
|
||||||
|
onAction: ($event) => this.importDevices($event)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
importDevices($event: Event) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeviceAction(action: EntityAction<Device | DeviceInfo>): boolean {
|
makePublic($event: Event, device: Device) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
this.dialogService.confirm(
|
||||||
|
this.translate.instant('device.make-public-device-title', {deviceName: device.name}),
|
||||||
|
this.translate.instant('device.make-public-device-text'),
|
||||||
|
this.translate.instant('action.no'),
|
||||||
|
this.translate.instant('action.yes'),
|
||||||
|
true
|
||||||
|
).subscribe((res) => {
|
||||||
|
if (res) {
|
||||||
|
this.deviceService.makeDevicePublic(device.id.id).subscribe(
|
||||||
|
() => {
|
||||||
|
this.config.table.updateData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
assignToCustomer($event: Event, device: Device) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
unassignFromCustomer($event: Event, device: DeviceInfo) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
const isPublic = device.customerIsPublic;
|
||||||
|
let title;
|
||||||
|
let content;
|
||||||
|
if (isPublic) {
|
||||||
|
title = this.translate.instant('device.make-private-device-title', {deviceName: device.name});
|
||||||
|
content = this.translate.instant('device.make-private-device-text');
|
||||||
|
} else {
|
||||||
|
title = this.translate.instant('device.unassign-device-title', {deviceName: device.name});
|
||||||
|
content = this.translate.instant('device.unassign-device-text');
|
||||||
|
}
|
||||||
|
this.dialogService.confirm(
|
||||||
|
this.translate.instant(title),
|
||||||
|
this.translate.instant(content),
|
||||||
|
this.translate.instant('action.no'),
|
||||||
|
this.translate.instant('action.yes'),
|
||||||
|
true
|
||||||
|
).subscribe((res) => {
|
||||||
|
if (res) {
|
||||||
|
this.deviceService.unassignDeviceFromCustomer(device.id.id).subscribe(
|
||||||
|
() => {
|
||||||
|
this.config.table.updateData();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
manageCredentials($event: Event, device: Device) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
this.dialog.open<DeviceCredentialsDialogComponent, DeviceCredentialsDialogData,
|
||||||
|
DeviceCredentials>(DeviceCredentialsDialogComponent, {
|
||||||
|
disableClose: true,
|
||||||
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
|
data: {
|
||||||
|
deviceId: device.id.id,
|
||||||
|
isReadOnly: this.config.componentsData.deviceScope === 'customer_user'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeviceAction(action: EntityAction<DeviceInfo>): boolean {
|
||||||
switch (action.action) {
|
switch (action.action) {
|
||||||
case 'makePublic':
|
case 'makePublic':
|
||||||
this.makePublic(action.event, action.entity);
|
this.makePublic(action.event, action.entity);
|
||||||
return true;
|
return true;
|
||||||
|
case 'assignToCustomer':
|
||||||
|
this.assignToCustomer(action.event, action.entity);
|
||||||
|
return true;
|
||||||
|
case 'unassignFromCustomer':
|
||||||
|
this.unassignFromCustomer(action.event, action.entity);
|
||||||
|
return true;
|
||||||
|
case 'manageCredentials':
|
||||||
|
this.manageCredentials(action.event, action.entity);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,10 +19,8 @@ import { UserService } from '@core/http/user.service';
|
|||||||
import {User} from '@shared/models/user.model';
|
import {User} from '@shared/models/user.model';
|
||||||
import {Authority} from '@shared/models/authority.enum';
|
import {Authority} from '@shared/models/authority.enum';
|
||||||
import {PageComponent} from '@shared/components/page.component';
|
import {PageComponent} from '@shared/components/page.component';
|
||||||
import { select, Store } from '@ngrx/store';
|
import {Store} from '@ngrx/store';
|
||||||
import {AppState} from '@core/core.state';
|
import {AppState} from '@core/core.state';
|
||||||
import { getCurrentAuthUser, selectAuthUser } from '@core/auth/auth.selectors';
|
|
||||||
import { mergeMap, take } from 'rxjs/operators';
|
|
||||||
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||||
import {HasConfirmForm} from '@core/guards/confirm-on-exit.guard';
|
import {HasConfirmForm} from '@core/guards/confirm-on-exit.guard';
|
||||||
import {ActionAuthUpdateUserDetails} from '@core/auth/auth.actions';
|
import {ActionAuthUpdateUserDetails} from '@core/auth/auth.actions';
|
||||||
|
|||||||
@ -122,6 +122,7 @@ export class EntityTableConfig<T extends BaseData<HasId>, P extends PageLink = P
|
|||||||
cellActionDescriptors: Array<CellActionDescriptor<T>> = [];
|
cellActionDescriptors: Array<CellActionDescriptor<T>> = [];
|
||||||
groupActionDescriptors: Array<GroupActionDescriptor<T>> = [];
|
groupActionDescriptors: Array<GroupActionDescriptor<T>> = [];
|
||||||
headerActionDescriptors: Array<HeaderActionDescriptor> = [];
|
headerActionDescriptors: Array<HeaderActionDescriptor> = [];
|
||||||
|
addActionDescriptors: Array<HeaderActionDescriptor> = [];
|
||||||
headerComponent: Type<EntityTableHeaderComponent<T>>;
|
headerComponent: Type<EntityTableHeaderComponent<T>>;
|
||||||
addEntity: CreateEntityOperation<T> = null;
|
addEntity: CreateEntityOperation<T> = null;
|
||||||
detailsReadonly: EntityBooleanFunction<T> = () => false;
|
detailsReadonly: EntityBooleanFunction<T> = () => false;
|
||||||
|
|||||||
@ -42,11 +42,32 @@
|
|||||||
asButton historyOnly></tb-timewindow>
|
asButton historyOnly></tb-timewindow>
|
||||||
<tb-anchor #entityTableHeader></tb-anchor>
|
<tb-anchor #entityTableHeader></tb-anchor>
|
||||||
<span fxFlex *ngIf="!this.entitiesTableConfig.headerComponent"></span>
|
<span fxFlex *ngIf="!this.entitiesTableConfig.headerComponent"></span>
|
||||||
<button mat-button mat-icon-button [disabled]="isLoading$ | async" [fxShow]="addEnabled()" (click)="addEntity($event)"
|
<div [fxShow]="addEnabled()">
|
||||||
|
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
|
*ngIf="!this.entitiesTableConfig.addActionDescriptors.length; else addActions"
|
||||||
|
(click)="addEntity($event)"
|
||||||
matTooltip="{{ translations.add | translate }}"
|
matTooltip="{{ translations.add | translate }}"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>add</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
<ng-template #addActions>
|
||||||
|
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
|
matTooltip="{{ translations.add | translate }}"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
[matMenuTriggerFor]="addActionsMenu">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-menu #addActionsMenu="matMenu" xPosition="before">
|
||||||
|
<button mat-menu-item *ngFor="let actionDescriptor of this.entitiesTableConfig.addActionDescriptors"
|
||||||
|
[disabled]="isLoading$ | async"
|
||||||
|
[fxShow]="actionDescriptor.isEnabled()"
|
||||||
|
(click)="actionDescriptor.onAction($event)">
|
||||||
|
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
|
||||||
|
<span>{{ actionDescriptor.name }}</span>
|
||||||
|
</button>
|
||||||
|
</mat-menu>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
|
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
|
||||||
[fxShow]="actionDescriptor.isEnabled()" *ngFor="let actionDescriptor of headerActionDescriptors"
|
[fxShow]="actionDescriptor.isEnabled()" *ngFor="let actionDescriptor of headerActionDescriptors"
|
||||||
matTooltip="{{ actionDescriptor.name }}"
|
matTooltip="{{ actionDescriptor.name }}"
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright © 2016-2019 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]="selectEntityFormGroup" class="mat-block">
|
||||||
|
<input matInput type="text" placeholder="{{ entityText | translate }}"
|
||||||
|
#entityInput
|
||||||
|
formControlName="entity"
|
||||||
|
[required]="required"
|
||||||
|
[matAutocomplete]="entityAutocomplete">
|
||||||
|
<button *ngIf="selectEntityFormGroup.get('entity').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 #entityAutocomplete="matAutocomplete" [displayWith]="displayEntityFn">
|
||||||
|
<mat-option *ngFor="let entity of filteredEntities | async" [value]="entity">
|
||||||
|
<span [innerHTML]="entity.name | highlight:searchText"></span>
|
||||||
|
</mat-option>
|
||||||
|
<mat-option *ngIf="!(filteredEntities | async)?.length" [value]="null">
|
||||||
|
<span>
|
||||||
|
{{ translate.get(noEntitiesMatchingText, {entity: searchText}) | async }}
|
||||||
|
</span>
|
||||||
|
</mat-option>
|
||||||
|
</mat-autocomplete>
|
||||||
|
<mat-error *ngIf="selectEntityFormGroup.get('entity').hasError('required')">
|
||||||
|
{{ entityRequiredText | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
@ -0,0 +1,274 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 The Thingsboard Authors
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
|
||||||
|
import {AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild} from '@angular/core';
|
||||||
|
import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
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 {AliasEntityType, EntityType} from '@shared/models/entity-type.models';
|
||||||
|
import {BaseData} from '@shared/models/base-data';
|
||||||
|
import {EntityId} from '@shared/models/id/entity-id';
|
||||||
|
import {EntityService} from '@core/http/entity.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-entity-autocomplete',
|
||||||
|
templateUrl: './entity-autocomplete.component.html',
|
||||||
|
styleUrls: [],
|
||||||
|
providers: [{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => EntityAutocompleteComponent),
|
||||||
|
multi: true
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit, AfterViewInit {
|
||||||
|
|
||||||
|
selectEntityFormGroup: FormGroup;
|
||||||
|
|
||||||
|
modelValue: string | null;
|
||||||
|
|
||||||
|
entityTypeValue: EntityType | AliasEntityType;
|
||||||
|
|
||||||
|
entitySubtypeValue: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set entityType(entityType: EntityType) {
|
||||||
|
if (this.entityTypeValue !== entityType) {
|
||||||
|
this.entityTypeValue = entityType;
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set entitySubtype(entitySubtype: string) {
|
||||||
|
if (this.entitySubtypeValue !== entitySubtype) {
|
||||||
|
this.entitySubtypeValue = entitySubtype;
|
||||||
|
const currentEntity = this.getCurrentEntity();
|
||||||
|
if (currentEntity) {
|
||||||
|
if ((currentEntity as any).type !== this.entitySubtypeValue) {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
excludeEntityIds: Array<string>;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
required: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
@ViewChild('entityInput', {static: true}) entityInput: ElementRef;
|
||||||
|
|
||||||
|
entityText: string;
|
||||||
|
noEntitiesMatchingText: string;
|
||||||
|
entityRequiredText: string;
|
||||||
|
|
||||||
|
filteredEntities: Observable<Array<BaseData<EntityId>>>;
|
||||||
|
|
||||||
|
private searchText = '';
|
||||||
|
|
||||||
|
private propagateChange = (v: any) => { };
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>,
|
||||||
|
public translate: TranslateService,
|
||||||
|
private entityService: EntityService,
|
||||||
|
private fb: FormBuilder) {
|
||||||
|
this.selectEntityFormGroup = this.fb.group({
|
||||||
|
entity: [null]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.filteredEntities = this.selectEntityFormGroup.get('dashboard').valueChanges
|
||||||
|
.pipe(
|
||||||
|
tap(value => {
|
||||||
|
let modelValue;
|
||||||
|
if (typeof value === 'string' || !value) {
|
||||||
|
modelValue = null;
|
||||||
|
} else {
|
||||||
|
modelValue = value.id.id;
|
||||||
|
}
|
||||||
|
this.updateView(modelValue);
|
||||||
|
}),
|
||||||
|
startWith<string | BaseData<EntityId>>(''),
|
||||||
|
map(value => value ? (typeof value === 'string' ? value : value.name) : ''),
|
||||||
|
mergeMap(name => this.fetchEntities(name) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {}
|
||||||
|
|
||||||
|
load(): void {
|
||||||
|
if (this.entityTypeValue) {
|
||||||
|
switch (this.entityTypeValue) {
|
||||||
|
case EntityType.ASSET:
|
||||||
|
this.entityText = 'asset.asset';
|
||||||
|
this.noEntitiesMatchingText = 'asset.no-assets-matching';
|
||||||
|
this.entityRequiredText = 'asset.asset-required';
|
||||||
|
break;
|
||||||
|
case EntityType.DEVICE:
|
||||||
|
this.entityText = 'device.device';
|
||||||
|
this.noEntitiesMatchingText = 'device.no-devices-matching';
|
||||||
|
this.entityRequiredText = 'device.device-required';
|
||||||
|
break;
|
||||||
|
case EntityType.ENTITY_VIEW:
|
||||||
|
this.entityText = 'entity-view.entity-view';
|
||||||
|
this.noEntitiesMatchingText = 'entity-view.no-entity-views-matching';
|
||||||
|
this.entityRequiredText = 'entity-view.entity-view-required';
|
||||||
|
break;
|
||||||
|
case EntityType.RULE_CHAIN:
|
||||||
|
this.entityText = 'rulechain.rulechain';
|
||||||
|
this.noEntitiesMatchingText = 'rulechain.no-rulechains-matching';
|
||||||
|
this.entityRequiredText = 'rulechain.rulechain-required';
|
||||||
|
break;
|
||||||
|
case EntityType.TENANT:
|
||||||
|
this.entityText = 'tenant.tenant';
|
||||||
|
this.noEntitiesMatchingText = 'tenant.no-tenants-matching';
|
||||||
|
this.entityRequiredText = 'tenant.tenant-required';
|
||||||
|
break;
|
||||||
|
case EntityType.CUSTOMER:
|
||||||
|
this.entityText = 'customer.customer';
|
||||||
|
this.noEntitiesMatchingText = 'customer.no-customers-matching';
|
||||||
|
this.entityRequiredText = 'customer.customer-required';
|
||||||
|
break;
|
||||||
|
case EntityType.USER:
|
||||||
|
this.entityText = 'user.user';
|
||||||
|
this.noEntitiesMatchingText = 'user.no-users-matching';
|
||||||
|
this.entityRequiredText = 'user.user-required';
|
||||||
|
break;
|
||||||
|
case EntityType.DASHBOARD:
|
||||||
|
this.entityText = 'dashboard.dashboard';
|
||||||
|
this.noEntitiesMatchingText = 'dashboard.no-dashboards-matching';
|
||||||
|
this.entityRequiredText = 'dashboard.dashboard-required';
|
||||||
|
break;
|
||||||
|
case EntityType.ALARM:
|
||||||
|
this.entityText = 'alarm.alarm';
|
||||||
|
this.noEntitiesMatchingText = 'alarm.no-alarms-matching';
|
||||||
|
this.entityRequiredText = 'alarm.alarm-required';
|
||||||
|
break;
|
||||||
|
case AliasEntityType.CURRENT_CUSTOMER:
|
||||||
|
this.entityText = 'customer.default-customer';
|
||||||
|
this.noEntitiesMatchingText = 'customer.no-customers-matching';
|
||||||
|
this.entityRequiredText = 'customer.default-customer-required';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const currentEntity = this.getCurrentEntity();
|
||||||
|
if (currentEntity) {
|
||||||
|
const currentEntityType = currentEntity.id.entityType;
|
||||||
|
if (this.entityTypeValue && currentEntityType !== this.entityTypeValue) {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentEntity(): BaseData<EntityId> | null {
|
||||||
|
const currentEntity = this.selectEntityFormGroup.get('entity').value;
|
||||||
|
if (currentEntity && typeof currentEntity !== 'string') {
|
||||||
|
return currentEntity as BaseData<EntityId>;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: string | null): void {
|
||||||
|
this.searchText = '';
|
||||||
|
if (value != null) {
|
||||||
|
let targetEntityType = this.entityTypeValue;
|
||||||
|
if (targetEntityType === AliasEntityType.CURRENT_CUSTOMER) {
|
||||||
|
targetEntityType = EntityType.CUSTOMER;
|
||||||
|
}
|
||||||
|
this.entityService.getEntity(targetEntityType, value).subscribe(
|
||||||
|
(entity) => {
|
||||||
|
this.modelValue = entity.id.id;
|
||||||
|
this.selectEntityFormGroup.get('entity').patchValue(entity, {emitEvent: true});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.modelValue = null;
|
||||||
|
this.selectEntityFormGroup.get('entity').patchValue(null, {emitEvent: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.selectEntityFormGroup.get('entity').patchValue(null, {emitEvent: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateView(value: string | null) {
|
||||||
|
if (this.modelValue !== value) {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.propagateChange(this.modelValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
|
||||||
|
return entity ? entity.name : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchEntities(searchText?: string): Observable<Array<BaseData<EntityId>>> {
|
||||||
|
this.searchText = searchText;
|
||||||
|
let targetEntityType = this.entityTypeValue;
|
||||||
|
if (targetEntityType === AliasEntityType.CURRENT_CUSTOMER) {
|
||||||
|
targetEntityType = EntityType.CUSTOMER;
|
||||||
|
}
|
||||||
|
return this.entityService.getEntitiesByNameFilter(targetEntityType, searchText,
|
||||||
|
50, this.entitySubtypeValue, false, true).pipe(
|
||||||
|
map((data) => {
|
||||||
|
if (data) {
|
||||||
|
if (this.excludeEntityIds && this.excludeEntityIds.length) {
|
||||||
|
const entities: Array<BaseData<EntityId>> = [];
|
||||||
|
data.forEach((entity) => {
|
||||||
|
if (this.excludeEntityIds.indexOf(entity.id.id) === -1) {
|
||||||
|
entities.push(entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return entities;
|
||||||
|
} else {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.selectEntityFormGroup.get('entity').patchValue(null, {emitEvent: true});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.entityInput.nativeElement.blur();
|
||||||
|
this.entityInput.nativeElement.focus();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
51
ui-ngx/src/app/shared/models/alarm.models.ts
Normal file
51
ui-ngx/src/app/shared/models/alarm.models.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {AssetId} from '@shared/models/id/asset-id';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {CustomerId} from '@shared/models/id/customer-id';
|
||||||
|
import {AlarmId} from '@shared/models/id/alarm-id';
|
||||||
|
import {EntityId} from '@shared/models/id/entity-id';
|
||||||
|
|
||||||
|
export enum AlarmSeverity {
|
||||||
|
CRITICAL = 'CRITICAL',
|
||||||
|
MAJOR = 'MAJOR',
|
||||||
|
MINOR = 'MINOR',
|
||||||
|
WARNING = 'WARNING',
|
||||||
|
INDETERMINATE = 'INDETERMINATE'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AlarmStatus {
|
||||||
|
ACTIVE_UNACK = 'ACTIVE_UNACK',
|
||||||
|
ACTIVE_ACK = 'ACTIVE_ACK',
|
||||||
|
CLEARED_UNACK = 'CLEARED_UNACK',
|
||||||
|
CLEARED_ACK = 'CLEARED_ACK'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Alarm extends BaseData<AlarmId> {
|
||||||
|
tenantId: TenantId;
|
||||||
|
type: string;
|
||||||
|
originator: EntityId;
|
||||||
|
severity: AlarmSeverity;
|
||||||
|
status: AlarmStatus;
|
||||||
|
startTs: number;
|
||||||
|
endTs: number;
|
||||||
|
ackTs: number;
|
||||||
|
clearTs: number;
|
||||||
|
propagate: boolean;
|
||||||
|
details?: any;
|
||||||
|
}
|
||||||
34
ui-ngx/src/app/shared/models/asset.models.ts
Normal file
34
ui-ngx/src/app/shared/models/asset.models.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {AssetId} from './id/asset-id';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {CustomerId} from '@shared/models/id/customer-id';
|
||||||
|
import {DeviceCredentialsId} from '@shared/models/id/device-credentials-id';
|
||||||
|
|
||||||
|
export interface Asset extends BaseData<AssetId> {
|
||||||
|
tenantId: TenantId;
|
||||||
|
customerId: CustomerId;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
additionalInfo?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetInfo extends Asset {
|
||||||
|
customerTitle: string;
|
||||||
|
customerIsPublic: boolean;
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ import {BaseData} from '@shared/models/base-data';
|
|||||||
import {DeviceId} from './id/device-id';
|
import {DeviceId} from './id/device-id';
|
||||||
import {TenantId} from '@shared/models/id/tenant-id';
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
import {CustomerId} from '@shared/models/id/customer-id';
|
import {CustomerId} from '@shared/models/id/customer-id';
|
||||||
|
import {DeviceCredentialsId} from '@shared/models/id/device-credentials-id';
|
||||||
|
|
||||||
export interface Device extends BaseData<DeviceId> {
|
export interface Device extends BaseData<DeviceId> {
|
||||||
tenantId: TenantId;
|
tenantId: TenantId;
|
||||||
@ -32,3 +33,22 @@ export interface DeviceInfo extends Device {
|
|||||||
customerTitle: string;
|
customerTitle: string;
|
||||||
customerIsPublic: boolean;
|
customerIsPublic: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum DeviceCredentialsType {
|
||||||
|
ACCESS_TOKEN = 'ACCESS_TOKEN',
|
||||||
|
X509_CERTIFICATE = 'X509_CERTIFICATE'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const credentialTypeNames = new Map<DeviceCredentialsType, string>(
|
||||||
|
[
|
||||||
|
[DeviceCredentialsType.ACCESS_TOKEN, 'Access token'],
|
||||||
|
[DeviceCredentialsType.X509_CERTIFICATE, 'X.509 Certificate'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface DeviceCredentials extends BaseData<DeviceCredentialsId> {
|
||||||
|
deviceId: DeviceId;
|
||||||
|
credentialsType: DeviceCredentialsType;
|
||||||
|
credentialsId: string;
|
||||||
|
credentialsValue: string;
|
||||||
|
}
|
||||||
|
|||||||
@ -31,6 +31,10 @@ export enum EntityType {
|
|||||||
WIDGET_TYPE = 'WIDGET_TYPE'
|
WIDGET_TYPE = 'WIDGET_TYPE'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AliasEntityType {
|
||||||
|
CURRENT_CUSTOMER = 'CURRENT_CUSTOMER'
|
||||||
|
}
|
||||||
|
|
||||||
export interface EntityTypeTranslation {
|
export interface EntityTypeTranslation {
|
||||||
type: string;
|
type: string;
|
||||||
typePlural: string;
|
typePlural: string;
|
||||||
|
|||||||
50
ui-ngx/src/app/shared/models/entity-view.models.ts
Normal file
50
ui-ngx/src/app/shared/models/entity-view.models.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {AssetId} from './id/asset-id';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {CustomerId} from '@shared/models/id/customer-id';
|
||||||
|
import {EntityViewId} from '@shared/models/id/entity-view-id';
|
||||||
|
import {EntityId} from '@shared/models/id/entity-id';
|
||||||
|
|
||||||
|
export interface AttributesEntityView {
|
||||||
|
cs: Array<string>;
|
||||||
|
ss: Array<string>;
|
||||||
|
sh: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TelemetryEntityView {
|
||||||
|
timeseries: Array<string>;
|
||||||
|
attributes: AttributesEntityView;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityView extends BaseData<EntityViewId> {
|
||||||
|
tenantId: TenantId;
|
||||||
|
customerId: CustomerId;
|
||||||
|
entityId: EntityId;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
keys: TelemetryEntityView;
|
||||||
|
startTimeMs: number;
|
||||||
|
endTimeMs: number;
|
||||||
|
additionalInfo?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityViewInfo extends EntityView {
|
||||||
|
customerTitle: string;
|
||||||
|
customerIsPublic: boolean;
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/alarm-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/alarm-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class AlarmId implements EntityId {
|
||||||
|
entityType = EntityType.ALARM;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/asset-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/asset-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class AssetId implements EntityId {
|
||||||
|
entityType = EntityType.ASSET;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
ui-ngx/src/app/shared/models/id/device-credentials-id.ts
Normal file
24
ui-ngx/src/app/shared/models/id/device-credentials-id.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { HasUUID } from '@shared/models/id/has-uuid';
|
||||||
|
|
||||||
|
export class DeviceCredentialsId implements HasUUID {
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/entity-view-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/entity-view-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class EntityViewId implements EntityId {
|
||||||
|
entityType = EntityType.ENTITY_VIEW;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/rule-chain-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/rule-chain-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class RuleChainId implements EntityId {
|
||||||
|
entityType = EntityType.RULE_CHAIN;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/rule-node-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/rule-node-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class RuleNodeId implements EntityId {
|
||||||
|
entityType = EntityType.RULE_NODE;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/widget-type-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/widget-type-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class WidgetTypeId implements EntityId {
|
||||||
|
entityType = EntityType.WIDGET_TYPE;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/id/widgets-bundle-id.ts
Normal file
26
ui-ngx/src/app/shared/models/id/widgets-bundle-id.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 { EntityId } from './entity-id';
|
||||||
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
|
|
||||||
|
export class WidgetsBundleId implements EntityId {
|
||||||
|
entityType = EntityType.WIDGETS_BUNDLE;
|
||||||
|
id: string;
|
||||||
|
constructor(id: string) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
ui-ngx/src/app/shared/models/rule-chain.models.ts
Normal file
37
ui-ngx/src/app/shared/models/rule-chain.models.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {AssetId} from '@shared/models/id/asset-id';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {CustomerId} from '@shared/models/id/customer-id';
|
||||||
|
import {RuleChainId} from '@shared/models/id/rule-chain-id';
|
||||||
|
import {RuleNodeId} from '@shared/models/id/rule-node-id';
|
||||||
|
|
||||||
|
export interface RuleChainConfiguration {
|
||||||
|
todo: Array<any>;
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RuleChain extends BaseData<RuleChainId> {
|
||||||
|
tenantId: TenantId;
|
||||||
|
name: string;
|
||||||
|
firstRuleNodeId: RuleNodeId;
|
||||||
|
root: boolean;
|
||||||
|
debugMode: boolean;
|
||||||
|
configuration: RuleChainConfiguration;
|
||||||
|
additionalInfo?: any;
|
||||||
|
}
|
||||||
36
ui-ngx/src/app/shared/models/rule-node.models.ts
Normal file
36
ui-ngx/src/app/shared/models/rule-node.models.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {AssetId} from '@shared/models/id/asset-id';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {CustomerId} from '@shared/models/id/customer-id';
|
||||||
|
import {RuleChainId} from '@shared/models/id/rule-chain-id';
|
||||||
|
import {RuleNodeId} from '@shared/models/id/rule-node-id';
|
||||||
|
|
||||||
|
export interface RuleNodeConfiguration {
|
||||||
|
todo: Array<any>;
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RuleNode extends BaseData<RuleNodeId> {
|
||||||
|
ruleChainId: RuleChainId;
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
debugMode: boolean;
|
||||||
|
configuration: RuleNodeConfiguration;
|
||||||
|
additionalInfo?: any;
|
||||||
|
}
|
||||||
33
ui-ngx/src/app/shared/models/widget-type.models.ts
Normal file
33
ui-ngx/src/app/shared/models/widget-type.models.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {WidgetsBundleId} from '@shared/models/id/widgets-bundle-id';
|
||||||
|
import {WidgetTypeId} from '@shared/models/id/widget-type-id';
|
||||||
|
|
||||||
|
export interface WidgetTypeDescriptor {
|
||||||
|
todo: Array<any>;
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WidgetType extends BaseData<WidgetTypeId> {
|
||||||
|
tenantId: TenantId;
|
||||||
|
bundleAlias: string;
|
||||||
|
alias: string;
|
||||||
|
name: string;
|
||||||
|
descriptor: WidgetTypeDescriptor;
|
||||||
|
}
|
||||||
26
ui-ngx/src/app/shared/models/widgets-bundle.model.ts
Normal file
26
ui-ngx/src/app/shared/models/widgets-bundle.model.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2019 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 {BaseData} from '@shared/models/base-data';
|
||||||
|
import {TenantId} from '@shared/models/id/tenant-id';
|
||||||
|
import {WidgetsBundleId} from '@shared/models/id/widgets-bundle-id';
|
||||||
|
|
||||||
|
export interface WidgetsBundle extends BaseData<WidgetsBundleId> {
|
||||||
|
tenantId: TenantId;
|
||||||
|
alias: string;
|
||||||
|
title: string;
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
@ -80,6 +80,7 @@ import { HighlightPipe } from '@shared/pipe/highlight.pipe';
|
|||||||
import {DashboardAutocompleteComponent} from '@shared/components/dashboard-autocomplete.component';
|
import {DashboardAutocompleteComponent} from '@shared/components/dashboard-autocomplete.component';
|
||||||
import {EntitySubTypeAutocompleteComponent} from '@shared/components/entity/entity-subtype-autocomplete.component';
|
import {EntitySubTypeAutocompleteComponent} from '@shared/components/entity/entity-subtype-autocomplete.component';
|
||||||
import {EntitySubTypeSelectComponent} from './components/entity/entity-subtype-select.component';
|
import {EntitySubTypeSelectComponent} from './components/entity/entity-subtype-select.component';
|
||||||
|
import {EntityAutocompleteComponent} from './components/entity/entity-autocomplete.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
providers: [
|
providers: [
|
||||||
@ -122,6 +123,7 @@ import {EntitySubTypeSelectComponent} from './components/entity/entity-subtype-s
|
|||||||
DashboardAutocompleteComponent,
|
DashboardAutocompleteComponent,
|
||||||
EntitySubTypeAutocompleteComponent,
|
EntitySubTypeAutocompleteComponent,
|
||||||
EntitySubTypeSelectComponent,
|
EntitySubTypeSelectComponent,
|
||||||
|
EntityAutocompleteComponent,
|
||||||
NospacePipe,
|
NospacePipe,
|
||||||
MillisecondsToTimeStringPipe,
|
MillisecondsToTimeStringPipe,
|
||||||
EnumToArrayPipe,
|
EnumToArrayPipe,
|
||||||
@ -189,6 +191,7 @@ import {EntitySubTypeSelectComponent} from './components/entity/entity-subtype-s
|
|||||||
DashboardAutocompleteComponent,
|
DashboardAutocompleteComponent,
|
||||||
EntitySubTypeAutocompleteComponent,
|
EntitySubTypeAutocompleteComponent,
|
||||||
EntitySubTypeSelectComponent,
|
EntitySubTypeSelectComponent,
|
||||||
|
EntityAutocompleteComponent,
|
||||||
// ValueInputComponent,
|
// ValueInputComponent,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user