Commit 5a07a7aca495e86bc1b2a3df1b3969cca6ff6be0

Authored by deaflynx
1 parent af04f116

Merged UI-NGX with develop/3.0-edge-fixed

Showing 45 changed files with 2061 additions and 687 deletions
@@ -89,4 +89,18 @@ export class AssetService { @@ -89,4 +89,18 @@ export class AssetService {
89 return this.http.get<Asset>(`/api/tenant/assets?assetName=${assetName}`, defaultHttpOptionsFromConfig(config)); 89 return this.http.get<Asset>(`/api/tenant/assets?assetName=${assetName}`, defaultHttpOptionsFromConfig(config));
90 } 90 }
91 91
  92 + public assignAssetToEdge(edgeId: string, assetId: string, config?: RequestConfig): Observable<Asset> {
  93 + return this.http.post<Asset>(`/api/edge/${edgeId}/asset/${assetId}`, null, defaultHttpOptionsFromConfig(config));
  94 + }
  95 +
  96 + public unassignAssetFromEdge(assetId: string, config?: RequestConfig) {
  97 + return this.http.delete(`/api/edge/asset/${assetId}`, defaultHttpOptionsFromConfig(config));
  98 + }
  99 +
  100 + public getEdgeAssets(edgeId, pageLink: PageLink, type: string = '',
  101 + config?: RequestConfig): Observable<PageData<AssetInfo>> {
  102 + return this.http.get<PageData<AssetInfo>>(`/api/edge/${edgeId}/assets${pageLink.toQuery()}&type=${type}`,
  103 + defaultHttpOptionsFromConfig(config));
  104 + }
  105 +
92 } 106 }
@@ -53,7 +53,7 @@ export class ComponentDescriptorService { @@ -53,7 +53,7 @@ export class ComponentDescriptorService {
53 } 53 }
54 } 54 }
55 55
56 - public getComponentDescriptorsByTypes(componentTypes: Array<ComponentType>, 56 + public getComponentDescriptorsByTypes(componentTypes: Array<ComponentType>, type: string,
57 config?: RequestConfig): Observable<Array<ComponentDescriptor>> { 57 config?: RequestConfig): Observable<Array<ComponentDescriptor>> {
58 let result: ComponentDescriptor[] = []; 58 let result: ComponentDescriptor[] = [];
59 for (let i = componentTypes.length - 1; i >= 0; i--) { 59 for (let i = componentTypes.length - 1; i >= 0; i--) {
@@ -67,7 +67,7 @@ export class ComponentDescriptorService { @@ -67,7 +67,7 @@ export class ComponentDescriptorService {
67 if (!componentTypes.length) { 67 if (!componentTypes.length) {
68 return of(result); 68 return of(result);
69 } else { 69 } else {
70 - return this.http.get<Array<ComponentDescriptor>>(`/api/components?componentTypes=${componentTypes.join(',')}`, 70 + return this.http.get<Array<ComponentDescriptor>>(`/api/components/${type}?componentTypes=${componentTypes.join(',')}`,
71 defaultHttpOptionsFromConfig(config)).pipe( 71 defaultHttpOptionsFromConfig(config)).pipe(
72 map((componentDescriptors) => { 72 map((componentDescriptors) => {
73 componentDescriptors.forEach((componentDescriptor) => { 73 componentDescriptors.forEach((componentDescriptor) => {
@@ -157,4 +157,19 @@ export class DashboardService { @@ -157,4 +157,19 @@ export class DashboardService {
157 return this.stDiffObservable; 157 return this.stDiffObservable;
158 } 158 }
159 159
  160 + public getEdgeDashboards(edgeId: string, pageLink: PageLink, type: string = '',
  161 + config?: RequestConfig): Observable<PageData<DashboardInfo>> {
  162 + return this.http.get<PageData<DashboardInfo>>(`/api/edge/${edgeId}/dashboards${pageLink.toQuery()}&type=${type}`,
  163 + defaultHttpOptionsFromConfig(config))
  164 + }
  165 +
  166 + public assignDashboardToEdge(edgeId: string, dashboardId: string, config?: RequestConfig): Observable<Dashboard> {
  167 + return this.http.post<Dashboard>(`/api/edge/${edgeId}/dashboard/${dashboardId}`, null,
  168 + defaultHttpOptionsFromConfig(config));
  169 + }
  170 +
  171 + public unassignDashboardFromEdge(edgeId: string, dashboardId: string, config?: RequestConfig) {
  172 + return this.http.delete(`/api/edge/${edgeId}/dashboard/${dashboardId}`, defaultHttpOptionsFromConfig(config));
  173 + }
  174 +
160 } 175 }
@@ -143,4 +143,18 @@ export class DeviceService { @@ -143,4 +143,18 @@ export class DeviceService {
143 return this.http.delete(`/api/customer/device/${deviceName}/claim`, defaultHttpOptionsFromConfig(config)); 143 return this.http.delete(`/api/customer/device/${deviceName}/claim`, defaultHttpOptionsFromConfig(config));
144 } 144 }
145 145
  146 + public assignDeviceToEdge(edgeId: string, deviceId: string, config?: RequestConfig): Observable<Device> {
  147 + return this.http.post<Device>(`/api/edge/${edgeId}/device/${deviceId}`, defaultHttpOptionsFromConfig(config));
  148 + }
  149 +
  150 + public unassignDeviceFromEdge(deviceId: string, config?: RequestConfig) {
  151 + return this.http.delete(`/api/edge/device/${deviceId}`, defaultHttpOptionsFromConfig(config));
  152 + }
  153 +
  154 + public getEdgeDevices(edgeId: string, pageLink: PageLink, type: string = '',
  155 + config?: RequestConfig): Observable<PageData<DeviceInfo>> {
  156 + return this.http.get<PageData<DeviceInfo>>(`/api/edge/${edgeId}/devices${pageLink.toQuery()}&type=${type}`,
  157 + defaultHttpOptionsFromConfig(config))
  158 + }
  159 +
146 } 160 }
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Injectable } from '@angular/core';
  18 +import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
  19 +import { Observable } from 'rxjs';
  20 +import { HttpClient } from '@angular/common/http';
  21 +import { PageLink } from '@shared/models/page/page-link';
  22 +import { PageData } from '@shared/models/page/page-data';
  23 +import { EntitySubtype } from '@app/shared/models/entity-type.models';
  24 +import {Edge, EdgeInfo, EdgeSearchQuery } from "@shared/models/edge.models";
  25 +
  26 +@Injectable({
  27 + providedIn: 'root'
  28 +})
  29 +export class EdgeService {
  30 +
  31 + constructor(
  32 + private http: HttpClient
  33 + ) { }
  34 +
  35 + public getEdges(edgeIds: Array<string>, config?: RequestConfig): Observable<Array<Edge>> {
  36 + return this.http.get<Array<Edge>>(`/api/edges?edgeIds=${edgeIds.join(',')}`,
  37 + defaultHttpOptionsFromConfig(config));
  38 + }
  39 +
  40 + public getEdge(edgeId: string, config?: RequestConfig): Observable<EdgeInfo> {
  41 + return this.http.get<EdgeInfo>(`/api/edge/${edgeId}`, defaultHttpOptionsFromConfig(config));
  42 + }
  43 +
  44 + public saveEdge(edge: Edge, config?: RequestConfig): Observable<Edge> {
  45 + return this.http.post<Edge>('/api/edge', edge, defaultHttpOptionsFromConfig(config));
  46 + }
  47 +
  48 + public deleteEdge(edgeId: string, config?: RequestConfig) {
  49 + return this.http.delete(`/api/edge/${edgeId}`, defaultHttpOptionsFromConfig(config));
  50 + }
  51 +
  52 + public getEdgeTypes(config?: RequestConfig): Observable<Array<EntitySubtype>> {
  53 + return this.http.get<Array<EntitySubtype>>('/api/edge/types', defaultHttpOptionsFromConfig(config));
  54 + }
  55 +
  56 + public getTenantEdges(pageLink: PageLink, type: string = '',
  57 + config?: RequestConfig): Observable<PageData<EdgeInfo>> {
  58 + return this.http.get<PageData<EdgeInfo>>(`/api/tenant/edges${pageLink.toQuery()}&type=${type}`,
  59 + defaultHttpOptionsFromConfig(config));
  60 + }
  61 +
  62 + public getCustomerEdges(customerId: string, pageLink: PageLink, type: string = '',
  63 + config?: RequestConfig): Observable<PageData<EdgeInfo>> {
  64 + return this.http.get<PageData<EdgeInfo>>(`/api/customer/${customerId}/edges${pageLink.toQuery()}&type=${type}`,
  65 + defaultHttpOptionsFromConfig(config));
  66 + }
  67 +
  68 + public assignEdgeToCustomer(customerId: string, edgeId: string, config?: RequestConfig): Observable<Edge> {
  69 + return this.http.post<Edge>(`/api/customer/${customerId}/edge/${edgeId}`, null, defaultHttpOptionsFromConfig(config));
  70 + }
  71 +
  72 + public unassignEdgeFromCustomer(edgeId: string, config?: RequestConfig) {
  73 + return this.http.delete(`/api/customer/edge/${edgeId}`, defaultHttpOptionsFromConfig(config));
  74 + }
  75 +
  76 + public makeEdgePublic(edgeId: string, config?: RequestConfig): Observable<Edge> {
  77 + return this.http.post<Edge>(`/api/customer/public/edge/${edgeId}`, null, defaultHttpOptionsFromConfig(config));
  78 + }
  79 +
  80 + public setRootRuleChain(edgeId: string, ruleChainId: string, config?: RequestConfig): Observable<Edge> {
  81 + return this.http.post<Edge>(`/api/edge/${edgeId}/${ruleChainId}/root`, null, defaultHttpOptionsFromConfig(config));
  82 + }
  83 +
  84 + public getTenantEdgeInfos(pageLink: PageLink, type: string = '',
  85 + config?: RequestConfig): Observable<PageData<EdgeInfo>> {
  86 + return this.http.get<PageData<EdgeInfo>>(`/api/tenant/edgeInfos${pageLink.toQuery()}&type=${type}`,
  87 + defaultHttpOptionsFromConfig(config));
  88 + }
  89 +
  90 + public findByQuery(query: EdgeSearchQuery, config?: RequestConfig): Observable<Array<Edge>> {
  91 + return this.http.post<Array<Edge>>('/api/edges', query, defaultHttpOptionsFromConfig(config));
  92 + }
  93 +
  94 +}
@@ -83,4 +83,19 @@ export class EntityViewService { @@ -83,4 +83,19 @@ export class EntityViewService {
83 return this.http.post<Array<EntityView>>('/api/entityViews', query, defaultHttpOptionsFromConfig(config)); 83 return this.http.post<Array<EntityView>>('/api/entityViews', query, defaultHttpOptionsFromConfig(config));
84 } 84 }
85 85
  86 + public assignEntityViewToEdge(edgeId: string, entityViewId: string, config?: RequestConfig): Observable<EntityView> {
  87 + return this.http.post<EntityView>(`/api/edge/${edgeId}/entityView/${entityViewId}`, null,
  88 + defaultHttpOptionsFromConfig(config));
  89 + }
  90 +
  91 + public unassignEntityViewFromEdge(entityViewId: string, config?: RequestConfig) {
  92 + return this.http.delete(`/api/edge/entityView/${entityViewId}`, defaultHttpOptionsFromConfig(config));
  93 + }
  94 +
  95 + public getEdgeEntityViews(edgeId: string, pageLink: PageLink, type: string = '',
  96 + config?: RequestConfig): Observable<PageData<EntityViewInfo>> {
  97 + return this.http.get<PageData<EntityViewInfo>>(`/api/edge/${edgeId}/entityViews${pageLink.toQuery()}&type=${type}`,
  98 + defaultHttpOptionsFromConfig(config))
  99 + }
  100 +
86 } 101 }
@@ -57,6 +57,9 @@ import { Asset, AssetSearchQuery } from '@shared/models/asset.models'; @@ -57,6 +57,9 @@ import { Asset, AssetSearchQuery } from '@shared/models/asset.models';
57 import { Device, DeviceCredentialsType, DeviceSearchQuery } from '@shared/models/device.models'; 57 import { Device, DeviceCredentialsType, DeviceSearchQuery } from '@shared/models/device.models';
58 import { EntityViewSearchQuery } from '@shared/models/entity-view.models'; 58 import { EntityViewSearchQuery } from '@shared/models/entity-view.models';
59 import { AttributeService } from '@core/http/attribute.service'; 59 import { AttributeService } from '@core/http/attribute.service';
  60 +import { EdgeService } from "@core/http/edge.service";
  61 +import {EdgeSearchQuery} from "@shared/models/edge.models";
  62 +import {ruleChainType} from "@shared/models/rule-chain.models";
60 63
61 @Injectable({ 64 @Injectable({
62 providedIn: 'root' 65 providedIn: 'root'
@@ -67,6 +70,7 @@ export class EntityService { @@ -67,6 +70,7 @@ export class EntityService {
67 private http: HttpClient, 70 private http: HttpClient,
68 private store: Store<AppState>, 71 private store: Store<AppState>,
69 private deviceService: DeviceService, 72 private deviceService: DeviceService,
  73 + private edgeService: EdgeService,
70 private assetService: AssetService, 74 private assetService: AssetService,
71 private entityViewService: EntityViewService, 75 private entityViewService: EntityViewService,
72 private tenantService: TenantService, 76 private tenantService: TenantService,
@@ -90,6 +94,9 @@ export class EntityService { @@ -90,6 +94,9 @@ export class EntityService {
90 case EntityType.ASSET: 94 case EntityType.ASSET:
91 observable = this.assetService.getAsset(entityId, config); 95 observable = this.assetService.getAsset(entityId, config);
92 break; 96 break;
  97 + case EntityType.EDGE:
  98 + observable = this.edgeService.getEdge(entityId, config);
  99 + break;
93 case EntityType.ENTITY_VIEW: 100 case EntityType.ENTITY_VIEW:
94 observable = this.entityViewService.getEntityView(entityId, config); 101 observable = this.entityViewService.getEntityView(entityId, config);
95 break; 102 break;
@@ -157,6 +164,9 @@ export class EntityService { @@ -157,6 +164,9 @@ export class EntityService {
157 case EntityType.ASSET: 164 case EntityType.ASSET:
158 observable = this.assetService.getAssets(entityIds, config); 165 observable = this.assetService.getAssets(entityIds, config);
159 break; 166 break;
  167 + case EntityType.EDGE:
  168 + observable = this.edgeService.getEdges(entityIds, config);
  169 + break;
160 case EntityType.ENTITY_VIEW: 170 case EntityType.ENTITY_VIEW:
161 observable = this.getEntitiesByIdsObservable( 171 observable = this.getEntitiesByIdsObservable(
162 (id) => this.entityViewService.getEntityView(id, config), 172 (id) => this.entityViewService.getEntityView(id, config),
@@ -265,6 +275,14 @@ export class EntityService { @@ -265,6 +275,14 @@ export class EntityService {
265 entitiesObservable = this.assetService.getTenantAssetInfos(pageLink, subType, config); 275 entitiesObservable = this.assetService.getTenantAssetInfos(pageLink, subType, config);
266 } 276 }
267 break; 277 break;
  278 + case EntityType.EDGE:
  279 + pageLink.sortOrder.property = 'name';
  280 + if (authUser.authority === Authority.CUSTOMER_USER) {
  281 + entitiesObservable = this.edgeService.getCustomerEdges(customerId, pageLink, subType, config);
  282 + } else {
  283 + entitiesObservable = this.edgeService.getTenantEdgeInfos(pageLink, subType, config);
  284 + }
  285 + break;
268 case EntityType.ENTITY_VIEW: 286 case EntityType.ENTITY_VIEW:
269 pageLink.sortOrder.property = 'name'; 287 pageLink.sortOrder.property = 'name';
270 if (authUser.authority === Authority.CUSTOMER_USER) { 288 if (authUser.authority === Authority.CUSTOMER_USER) {
@@ -292,7 +310,12 @@ export class EntityService { @@ -292,7 +310,12 @@ export class EntityService {
292 break; 310 break;
293 case EntityType.RULE_CHAIN: 311 case EntityType.RULE_CHAIN:
294 pageLink.sortOrder.property = 'name'; 312 pageLink.sortOrder.property = 'name';
295 - entitiesObservable = this.ruleChainService.getRuleChains(pageLink, config); 313 + entitiesObservable = this.ruleChainService.getRuleChains(pageLink, ruleChainType.core, config);
  314 + // TODO: deaflynx: change solution
  315 + // console.log("route.routerState.snapshot.url", this.route.routerState.snapshot.url);
  316 + // if (this.route.url.includes('edges')) {
  317 + // entitiesObservable = this.ruleChainService.getRuleChains(pageLink, edgeRuleChainType, config);
  318 + // } else { entitiesObservable = this.ruleChainService.getRuleChains(pageLink, subType, config); }
296 break; 319 break;
297 case EntityType.DASHBOARD: 320 case EntityType.DASHBOARD:
298 pageLink.sortOrder.property = 'title'; 321 pageLink.sortOrder.property = 'title';
@@ -390,6 +413,8 @@ export class EntityService { @@ -390,6 +413,8 @@ export class EntityService {
390 return entityTypes.indexOf(EntityType.ASSET) > -1 ? true : false; 413 return entityTypes.indexOf(EntityType.ASSET) > -1 ? true : false;
391 case AliasFilterType.deviceType: 414 case AliasFilterType.deviceType:
392 return entityTypes.indexOf(EntityType.DEVICE) > -1 ? true : false; 415 return entityTypes.indexOf(EntityType.DEVICE) > -1 ? true : false;
  416 + case AliasFilterType.edgeType:
  417 + return entityTypes.indexOf(EntityType.EDGE) > -1 ? true : false;
393 case AliasFilterType.entityViewType: 418 case AliasFilterType.entityViewType:
394 return entityTypes.indexOf(EntityType.ENTITY_VIEW) > -1 ? true : false; 419 return entityTypes.indexOf(EntityType.ENTITY_VIEW) > -1 ? true : false;
395 case AliasFilterType.relationsQuery: 420 case AliasFilterType.relationsQuery:
@@ -416,6 +441,8 @@ export class EntityService { @@ -416,6 +441,8 @@ export class EntityService {
416 return entityTypes.indexOf(EntityType.ASSET) > -1 ? true : false; 441 return entityTypes.indexOf(EntityType.ASSET) > -1 ? true : false;
417 case AliasFilterType.deviceSearchQuery: 442 case AliasFilterType.deviceSearchQuery:
418 return entityTypes.indexOf(EntityType.DEVICE) > -1 ? true : false; 443 return entityTypes.indexOf(EntityType.DEVICE) > -1 ? true : false;
  444 + case AliasFilterType.edgeSearchQuery:
  445 + return entityTypes.indexOf(EntityType.EDGE) > -1 ? true : false;
419 case AliasFilterType.entityViewSearchQuery: 446 case AliasFilterType.entityViewSearchQuery:
420 return entityTypes.indexOf(EntityType.ENTITY_VIEW) > -1 ? true : false; 447 return entityTypes.indexOf(EntityType.ENTITY_VIEW) > -1 ? true : false;
421 } 448 }
@@ -449,6 +476,8 @@ export class EntityService { @@ -449,6 +476,8 @@ export class EntityService {
449 return entityType === EntityType.ASSET; 476 return entityType === EntityType.ASSET;
450 case AliasFilterType.deviceType: 477 case AliasFilterType.deviceType:
451 return entityType === EntityType.DEVICE; 478 return entityType === EntityType.DEVICE;
  479 + case AliasFilterType.edgeType:
  480 + return entityType === EntityType.EDGE;
452 case AliasFilterType.entityViewType: 481 case AliasFilterType.entityViewType:
453 return entityType === EntityType.ENTITY_VIEW; 482 return entityType === EntityType.ENTITY_VIEW;
454 case AliasFilterType.relationsQuery: 483 case AliasFilterType.relationsQuery:
@@ -457,6 +486,8 @@ export class EntityService { @@ -457,6 +486,8 @@ export class EntityService {
457 return entityType === EntityType.ASSET; 486 return entityType === EntityType.ASSET;
458 case AliasFilterType.deviceSearchQuery: 487 case AliasFilterType.deviceSearchQuery:
459 return entityType === EntityType.DEVICE; 488 return entityType === EntityType.DEVICE;
  489 + case AliasFilterType.edgeSearchQuery:
  490 + return entityType === EntityType.EDGE;
460 case AliasFilterType.entityViewSearchQuery: 491 case AliasFilterType.entityViewSearchQuery:
461 return entityType === EntityType.ENTITY_VIEW; 492 return entityType === EntityType.ENTITY_VIEW;
462 } 493 }
@@ -474,6 +505,7 @@ export class EntityService { @@ -474,6 +505,7 @@ export class EntityService {
474 case Authority.TENANT_ADMIN: 505 case Authority.TENANT_ADMIN:
475 entityTypes.push(EntityType.DEVICE); 506 entityTypes.push(EntityType.DEVICE);
476 entityTypes.push(EntityType.ASSET); 507 entityTypes.push(EntityType.ASSET);
  508 + entityTypes.push(EntityType.EDGE);
477 entityTypes.push(EntityType.ENTITY_VIEW); 509 entityTypes.push(EntityType.ENTITY_VIEW);
478 entityTypes.push(EntityType.TENANT); 510 entityTypes.push(EntityType.TENANT);
479 entityTypes.push(EntityType.CUSTOMER); 511 entityTypes.push(EntityType.CUSTOMER);
@@ -486,6 +518,7 @@ export class EntityService { @@ -486,6 +518,7 @@ export class EntityService {
486 case Authority.CUSTOMER_USER: 518 case Authority.CUSTOMER_USER:
487 entityTypes.push(EntityType.DEVICE); 519 entityTypes.push(EntityType.DEVICE);
488 entityTypes.push(EntityType.ASSET); 520 entityTypes.push(EntityType.ASSET);
  521 + entityTypes.push(EntityType.EDGE);
489 entityTypes.push(EntityType.ENTITY_VIEW); 522 entityTypes.push(EntityType.ENTITY_VIEW);
490 entityTypes.push(EntityType.CUSTOMER); 523 entityTypes.push(EntityType.CUSTOMER);
491 entityTypes.push(EntityType.DASHBOARD); 524 entityTypes.push(EntityType.DASHBOARD);
@@ -531,6 +564,7 @@ export class EntityService { @@ -531,6 +564,7 @@ export class EntityService {
531 entityFieldKeys.push(entityFields.type.keyName); 564 entityFieldKeys.push(entityFields.type.keyName);
532 break; 565 break;
533 case EntityType.DEVICE: 566 case EntityType.DEVICE:
  567 + case EntityType.EDGE:
534 case EntityType.ASSET: 568 case EntityType.ASSET:
535 entityFieldKeys.push(entityFields.name.keyName); 569 entityFieldKeys.push(entityFields.name.keyName);
536 entityFieldKeys.push(entityFields.type.keyName); 570 entityFieldKeys.push(entityFields.type.keyName);
@@ -704,6 +738,19 @@ export class EntityService { @@ -704,6 +738,19 @@ export class EntityService {
704 } 738 }
705 ) 739 )
706 ); 740 );
  741 + case AliasFilterType.edgeType:
  742 + return this.getEntitiesByNameFilter(EntityType.EDGE, filter.edgeNameFilter, maxItems,
  743 + filter.edgeType, {ignoreLoading: true, ignoreErrors: true}).pipe(
  744 + map((entities) => {
  745 + if (entities && entities.length || !failOnEmpty) {
  746 + result.entities = this.entitiesToEntitiesInfo(entities);
  747 + return result;
  748 + } else {
  749 + throw new Error();
  750 + }
  751 + }
  752 + )
  753 + );
707 case AliasFilterType.entityViewType: 754 case AliasFilterType.entityViewType:
708 return this.getEntitiesByNameFilter(EntityType.ENTITY_VIEW, filter.entityViewNameFilter, maxItems, 755 return this.getEntitiesByNameFilter(EntityType.ENTITY_VIEW, filter.entityViewNameFilter, maxItems,
709 filter.entityViewType, {ignoreLoading: true, ignoreErrors: true}).pipe( 756 filter.entityViewType, {ignoreLoading: true, ignoreErrors: true}).pipe(
@@ -763,6 +810,7 @@ export class EntityService { @@ -763,6 +810,7 @@ export class EntityService {
763 } 810 }
764 case AliasFilterType.assetSearchQuery: 811 case AliasFilterType.assetSearchQuery:
765 case AliasFilterType.deviceSearchQuery: 812 case AliasFilterType.deviceSearchQuery:
  813 + case AliasFilterType.edgeSearchQuery:
766 case AliasFilterType.entityViewSearchQuery: 814 case AliasFilterType.entityViewSearchQuery:
767 result.stateEntity = filter.rootStateEntity; 815 result.stateEntity = filter.rootStateEntity;
768 if (result.stateEntity && stateEntityId) { 816 if (result.stateEntity && stateEntityId) {
@@ -793,6 +841,10 @@ export class EntityService { @@ -793,6 +841,10 @@ export class EntityService {
793 const deviceSearchQuery = searchQuery as DeviceSearchQuery; 841 const deviceSearchQuery = searchQuery as DeviceSearchQuery;
794 deviceSearchQuery.deviceTypes = filter.deviceTypes; 842 deviceSearchQuery.deviceTypes = filter.deviceTypes;
795 findByQueryObservable = this.deviceService.findByQuery(deviceSearchQuery, {ignoreLoading: true, ignoreErrors: true}); 843 findByQueryObservable = this.deviceService.findByQuery(deviceSearchQuery, {ignoreLoading: true, ignoreErrors: true});
  844 + } else if (filter.type === AliasFilterType.edgeSearchQuery) {
  845 + const edgeSearchQuery = searchQuery as EdgeSearchQuery;
  846 + edgeSearchQuery.edgeTypes = filter.edgeTypes;
  847 + findByQueryObservable = this.edgeService.findByQuery(edgeSearchQuery, {ignoreLoading: true, ignoreErrors: true});
796 } else if (filter.type === AliasFilterType.entityViewSearchQuery) { 848 } else if (filter.type === AliasFilterType.entityViewSearchQuery) {
797 const entityViewSearchQuery = searchQuery as EntityViewSearchQuery; 849 const entityViewSearchQuery = searchQuery as EntityViewSearchQuery;
798 entityViewSearchQuery.entityViewTypes = filter.entityViewTypes; 850 entityViewSearchQuery.entityViewTypes = filter.entityViewTypes;
@@ -24,6 +24,7 @@ export * from './customer.service'; @@ -24,6 +24,7 @@ export * from './customer.service';
24 export * from './dashboard.service'; 24 export * from './dashboard.service';
25 export * from './device.service'; 25 export * from './device.service';
26 export * from './entity.service'; 26 export * from './entity.service';
  27 +export * from './edge.service';
27 export * from './entity-relation.service'; 28 export * from './entity-relation.service';
28 export * from './entity-view.service'; 29 export * from './entity-view.service';
29 export * from './event.service'; 30 export * from './event.service';
@@ -25,6 +25,7 @@ import { @@ -25,6 +25,7 @@ import {
25 RuleChain, 25 RuleChain,
26 RuleChainConnectionInfo, 26 RuleChainConnectionInfo,
27 RuleChainMetaData, 27 RuleChainMetaData,
  28 + ruleChainType,
28 ruleChainNodeComponent, 29 ruleChainNodeComponent,
29 ruleNodeTypeComponentTypes, 30 ruleNodeTypeComponentTypes,
30 unknownNodeComponent 31 unknownNodeComponent
@@ -59,8 +60,8 @@ export class RuleChainService { @@ -59,8 +60,8 @@ export class RuleChainService {
59 private translate: TranslateService 60 private translate: TranslateService
60 ) { } 61 ) { }
61 62
62 - public getRuleChains(pageLink: PageLink, config?: RequestConfig): Observable<PageData<RuleChain>> {  
63 - return this.http.get<PageData<RuleChain>>(`/api/ruleChains${pageLink.toQuery()}`, 63 + public getRuleChains(pageLink: PageLink, type: string, config?: RequestConfig): Observable<PageData<RuleChain>> {
  64 + return this.http.get<PageData<RuleChain>>(`/api/ruleChains${pageLink.toQuery()}&type=${type}`,
64 defaultHttpOptionsFromConfig(config)); 65 defaultHttpOptionsFromConfig(config));
65 } 66 }
66 67
@@ -110,12 +111,12 @@ export class RuleChainService { @@ -110,12 +111,12 @@ export class RuleChainService {
110 ); 111 );
111 } 112 }
112 113
113 - public getRuleNodeComponents(ruleNodeConfigResourcesModulesMap: {[key: string]: any}, config?: RequestConfig): 114 + public getRuleNodeComponents(ruleNodeConfigResourcesModulesMap: {[key: string]: any}, type: string, config?: RequestConfig):
114 Observable<Array<RuleNodeComponentDescriptor>> { 115 Observable<Array<RuleNodeComponentDescriptor>> {
115 if (this.ruleNodeComponents) { 116 if (this.ruleNodeComponents) {
116 return of(this.ruleNodeComponents); 117 return of(this.ruleNodeComponents);
117 } else { 118 } else {
118 - return this.loadRuleNodeComponents(config).pipe( 119 + return this.loadRuleNodeComponents(type, config).pipe(
119 mergeMap((components) => { 120 mergeMap((components) => {
120 return this.resolveRuleNodeComponentsUiResources(components, ruleNodeConfigResourcesModulesMap).pipe( 121 return this.resolveRuleNodeComponentsUiResources(components, ruleNodeConfigResourcesModulesMap).pipe(
121 map((ruleNodeComponents) => { 122 map((ruleNodeComponents) => {
@@ -198,8 +199,8 @@ export class RuleChainService { @@ -198,8 +199,8 @@ export class RuleChainService {
198 } 199 }
199 } 200 }
200 201
201 - private loadRuleNodeComponents(config?: RequestConfig): Observable<Array<RuleNodeComponentDescriptor>> {  
202 - return this.componentDescriptorService.getComponentDescriptorsByTypes(ruleNodeTypeComponentTypes, config).pipe( 202 + private loadRuleNodeComponents(type: string, config?: RequestConfig): Observable<Array<RuleNodeComponentDescriptor>> {
  203 + return this.componentDescriptorService.getComponentDescriptorsByTypes(ruleNodeTypeComponentTypes, type, config).pipe(
203 map((components) => { 204 map((components) => {
204 const ruleNodeComponents: RuleNodeComponentDescriptor[] = []; 205 const ruleNodeComponents: RuleNodeComponentDescriptor[] = [];
205 components.forEach((component) => { 206 components.forEach((component) => {
@@ -286,4 +287,40 @@ export class RuleChainService { @@ -286,4 +287,40 @@ export class RuleChainService {
286 ); 287 );
287 } 288 }
288 289
  290 + public getEdgeRuleChains(edgeId: string, pageLink: PageLink,
  291 + config?:RequestConfig): Observable<PageData<RuleChain>> {
  292 + return this.http.get<PageData<RuleChain>>(`/api/edge/${edgeId}/ruleChains${pageLink.toQuery()}`,
  293 + defaultHttpOptionsFromConfig(config) )
  294 + }
  295 +
  296 + public getEdgesRuleChains(pageLink: PageLink, config?: RequestConfig): Observable<PageData<RuleChain>> {
  297 + return this.getRuleChains(pageLink, ruleChainType.edge, config);
  298 + }
  299 +
  300 + public assignRuleChainToEdge(edgeId: string, ruleChainId: string, config?: RequestConfig): Observable<RuleChain> {
  301 + return this.http.post<RuleChain>(`/api/edge/${edgeId}/ruleChain/${ruleChainId}`, null,
  302 + defaultHttpOptionsFromConfig(config));
  303 + }
  304 +
  305 + public unassignRuleChainFromEdge(edgeId: string, ruleChainId: string, config?: RequestConfig) {
  306 + return this.http.delete(`/api/edge/${edgeId}/ruleChain/${ruleChainId}`, defaultHttpOptionsFromConfig(config));
  307 + }
  308 +
  309 + public setDefaultRootEdgeRuleChain(ruleChainId: string, config?: RequestConfig): Observable<RuleChain> {
  310 + return this.http.post<RuleChain>(`/api/ruleChain/${ruleChainId}/defaultRootEdge`, defaultHttpOptionsFromConfig(config));
  311 + }
  312 +
  313 + public addDefaultEdgeRuleChain(ruleChainId: string, config?: RequestConfig): Observable<RuleChain> {
  314 + return this.http.post<RuleChain>(`/api/ruleChain/${ruleChainId}/defaultEdge`, defaultHttpOptionsFromConfig(config));
  315 + }
  316 +
  317 + public removeDefaultEdgeRuleChain(ruleChainId: string, config?: RequestConfig): Observable<RuleChain> {
  318 + return this.http.delete<RuleChain>(`/api/ruleChain/${ruleChainId}/defaultEdge`, defaultHttpOptionsFromConfig(config));
  319 + }
  320 +
  321 + public getDefaultEdgeRuleChains(pageLink: PageLink, config?: RequestConfig): Observable<PageData<RuleChain>> {
  322 + return this.http.get<PageData<RuleChain>>(`/api/ruleChain/defaultEdgeRuleChains${pageLink.toQuery()}`,
  323 + defaultHttpOptionsFromConfig(config));
  324 + }
  325 +
289 } 326 }
@@ -180,9 +180,24 @@ export class MenuService { @@ -180,9 +180,24 @@ export class MenuService {
180 }, 180 },
181 { 181 {
182 name: 'rulechain.rulechains', 182 name: 'rulechain.rulechains',
183 - type: 'link', 183 + type: 'toggle',
184 path: '/ruleChains', 184 path: '/ruleChains',
185 - icon: 'settings_ethernet' 185 + height: '80px',
  186 + icon: 'settings_ethernet',
  187 + pages: [
  188 + {
  189 + name: 'rulechain.rulechains',
  190 + type: 'link',
  191 + path: '/ruleChains',
  192 + icon: 'settings_ethernet'
  193 + },
  194 + {
  195 + name: 'rulechain.edge-rulechains',
  196 + type: 'link',
  197 + path: '/edgesRuleChains',
  198 + icon: 'router'
  199 + }
  200 + ]
186 }, 201 },
187 { 202 {
188 name: 'customer.customers', 203 name: 'customer.customers',
@@ -209,6 +224,12 @@ export class MenuService { @@ -209,6 +224,12 @@ export class MenuService {
209 icon: 'view_quilt' 224 icon: 'view_quilt'
210 }, 225 },
211 { 226 {
  227 + name: 'edge.edges',
  228 + type: 'link',
  229 + path: '/edges',
  230 + icon: 'router'
  231 + },
  232 + {
212 name: 'widget.widget-library', 233 name: 'widget.widget-library',
213 type: 'link', 234 type: 'link',
214 path: '/widgets-bundles', 235 path: '/widgets-bundles',
@@ -240,6 +261,11 @@ export class MenuService { @@ -240,6 +261,11 @@ export class MenuService {
240 name: 'rulechain.rulechains', 261 name: 'rulechain.rulechains',
241 icon: 'settings_ethernet', 262 icon: 'settings_ethernet',
242 path: '/ruleChains' 263 path: '/ruleChains'
  264 + },
  265 + {
  266 + name: 'rulechain.edge-rulechains',
  267 + icon: 'router',
  268 + path: '/edgesRuleChains'
243 } 269 }
244 ] 270 ]
245 }, 271 },
@@ -284,6 +310,16 @@ export class MenuService { @@ -284,6 +310,16 @@ export class MenuService {
284 ] 310 ]
285 }, 311 },
286 { 312 {
  313 + name: 'edge.management',
  314 + places: [
  315 + {
  316 + name: 'edge.edges',
  317 + icon: 'router',
  318 + path: '/edges'
  319 + }
  320 + ]
  321 + },
  322 + {
287 name: 'dashboard.management', 323 name: 'dashboard.management',
288 places: [ 324 places: [
289 { 325 {
@@ -28,6 +28,7 @@ import { EntityViewService } from '@core/http/entity-view.service'; @@ -28,6 +28,7 @@ import { EntityViewService } from '@core/http/entity-view.service';
28 import { DashboardService } from '@core/http/dashboard.service'; 28 import { DashboardService } from '@core/http/dashboard.service';
29 import { DialogComponent } from '@shared/components/dialog.component'; 29 import { DialogComponent } from '@shared/components/dialog.component';
30 import { Router } from '@angular/router'; 30 import { Router } from '@angular/router';
  31 +import { EdgeService } from "@core/http/edge.service";
31 32
32 export interface AddEntitiesToCustomerDialogData { 33 export interface AddEntitiesToCustomerDialogData {
33 customerId: string; 34 customerId: string;
@@ -57,6 +58,7 @@ export class AddEntitiesToCustomerDialogComponent extends @@ -57,6 +58,7 @@ export class AddEntitiesToCustomerDialogComponent extends
57 @Inject(MAT_DIALOG_DATA) public data: AddEntitiesToCustomerDialogData, 58 @Inject(MAT_DIALOG_DATA) public data: AddEntitiesToCustomerDialogData,
58 private deviceService: DeviceService, 59 private deviceService: DeviceService,
59 private assetService: AssetService, 60 private assetService: AssetService,
  61 + private edgeService: EdgeService,
60 private entityViewService: EntityViewService, 62 private entityViewService: EntityViewService,
61 private dashboardService: DashboardService, 63 private dashboardService: DashboardService,
62 @SkipSelf() private errorStateMatcher: ErrorStateMatcher, 64 @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
@@ -79,6 +81,10 @@ export class AddEntitiesToCustomerDialogComponent extends @@ -79,6 +81,10 @@ export class AddEntitiesToCustomerDialogComponent extends
79 this.assignToCustomerTitle = 'asset.assign-asset-to-customer'; 81 this.assignToCustomerTitle = 'asset.assign-asset-to-customer';
80 this.assignToCustomerText = 'asset.assign-asset-to-customer-text'; 82 this.assignToCustomerText = 'asset.assign-asset-to-customer-text';
81 break; 83 break;
  84 + case EntityType.EDGE:
  85 + this.assignToCustomerTitle = 'edge.assign-edge-to-customer';
  86 + this.assignToCustomerText = 'edge.assign-edge-to-customer-text';
  87 + break;
82 case EntityType.ENTITY_VIEW: 88 case EntityType.ENTITY_VIEW:
83 this.assignToCustomerTitle = 'entity-view.assign-entity-view-to-customer'; 89 this.assignToCustomerTitle = 'entity-view.assign-entity-view-to-customer';
84 this.assignToCustomerText = 'entity-view.assign-entity-view-to-customer-text'; 90 this.assignToCustomerText = 'entity-view.assign-entity-view-to-customer-text';
@@ -122,6 +128,8 @@ export class AddEntitiesToCustomerDialogComponent extends @@ -122,6 +128,8 @@ export class AddEntitiesToCustomerDialogComponent extends
122 return this.deviceService.assignDeviceToCustomer(customerId, entityId); 128 return this.deviceService.assignDeviceToCustomer(customerId, entityId);
123 case EntityType.ASSET: 129 case EntityType.ASSET:
124 return this.assetService.assignAssetToCustomer(customerId, entityId); 130 return this.assetService.assignAssetToCustomer(customerId, entityId);
  131 + case EntityType.EDGE:
  132 + return this.edgeService.assignEdgeToCustomer(customerId, entityId);
125 case EntityType.ENTITY_VIEW: 133 case EntityType.ENTITY_VIEW:
126 return this.entityViewService.assignEntityViewToCustomer(customerId, entityId); 134 return this.entityViewService.assignEntityViewToCustomer(customerId, entityId);
127 case EntityType.DASHBOARD: 135 case EntityType.DASHBOARD:
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<form [formGroup]="addEntitiesToEdgeFormGroup" (ngSubmit)="assign()">
  19 + <mat-toolbar fxLayout="row" color="primary">
  20 + <h2>{{ assignToEdgeTitle | translate }}</h2>
  21 + <span fxFlex></span>
  22 + <button mat-button mat-icon-button
  23 + (click)="cancel()"
  24 + type="button">
  25 + <mat-icon class="material-icons">close</mat-icon>
  26 + </button>
  27 + </mat-toolbar>
  28 + <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
  29 + </mat-progress-bar>
  30 + <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
  31 + <div mat-dialog-content>
  32 + <fieldset [disabled]="isLoading$ | async">
  33 + <span>{{ assignToEdgeText | translate }}</span>
  34 + <tb-entity-list
  35 + formControlName="entityIds"
  36 + required
  37 + [entityType]="entityType"
  38 + >
  39 + </tb-entity-list>
  40 + </fieldset>
  41 + </div>
  42 + <div mat-dialog-actions fxLayoutAlign="end center">
  43 + <button mat-raised-button color="primary"
  44 + type="submit"
  45 + [disabled]="(isLoading$ | async) || addEntitiesToEdgeFormGroup.invalid
  46 + || !addEntitiesToEdgeFormGroup.dirty">
  47 + {{ 'action.assign' | translate }}
  48 + </button>
  49 + <button mat-button color="primary"
  50 + style="margin-right: 20px;"
  51 + type="button"
  52 + [disabled]="(isLoading$ | async)"
  53 + (click)="cancel()" cdkFocusInitial>
  54 + {{ 'action.cancel' | translate }}
  55 + </button>
  56 + </div>
  57 +</form>
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Component, Inject, OnInit, SkipSelf } from '@angular/core';
  18 +import { ErrorStateMatcher } from '@angular/material/core';
  19 +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
  20 +import { Store } from '@ngrx/store';
  21 +import { AppState } from '@core/core.state';
  22 +import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
  23 +import { DeviceService } from '@core/http/device.service';
  24 +import { EdgeService } from "@core/http/edge.service";
  25 +import { EntityType } from '@shared/models/entity-type.models';
  26 +import { forkJoin, Observable } from 'rxjs';
  27 +import { AssetService } from '@core/http/asset.service';
  28 +import { EntityViewService } from '@core/http/entity-view.service';
  29 +import { DashboardService } from '@core/http/dashboard.service';
  30 +import { DialogComponent } from '@shared/components/dialog.component';
  31 +import { Router } from '@angular/router';
  32 +import { RuleChainService } from "@core/http/rule-chain.service";
  33 +
  34 +export interface AddEntitiesToEdgeDialogData {
  35 + edgeId: string;
  36 + entityType: EntityType;
  37 +}
  38 +
  39 +@Component({
  40 + selector: 'tb-add-entities-to-edge-dialog',
  41 + templateUrl: './add-entities-to-edge-dialog.component.html',
  42 + providers: [{provide: ErrorStateMatcher, useExisting: AddEntitiesToEdgeDialogComponent}],
  43 + styleUrls: []
  44 +})
  45 +export class AddEntitiesToEdgeDialogComponent extends
  46 + DialogComponent<AddEntitiesToEdgeDialogComponent, boolean> implements OnInit, ErrorStateMatcher {
  47 +
  48 + addEntitiesToEdgeFormGroup: FormGroup;
  49 +
  50 + submitted = false;
  51 +
  52 + entityType: EntityType;
  53 +
  54 + assignToEdgeTitle: string;
  55 + assignToEdgeText: string;
  56 +
  57 + constructor(protected store: Store<AppState>,
  58 + protected router: Router,
  59 + @Inject(MAT_DIALOG_DATA) public data: AddEntitiesToEdgeDialogData,
  60 + private deviceService: DeviceService,
  61 + private edgeService: EdgeService,
  62 + private assetService: AssetService,
  63 + private entityViewService: EntityViewService,
  64 + private dashboardService: DashboardService,
  65 + private ruleChainService: RuleChainService,
  66 + @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
  67 + public dialogRef: MatDialogRef<AddEntitiesToEdgeDialogComponent, boolean>,
  68 + public fb: FormBuilder) {
  69 + super(store, router, dialogRef);
  70 + this.entityType = data.entityType;
  71 + }
  72 +
  73 + ngOnInit(): void {
  74 + this.addEntitiesToEdgeFormGroup = this.fb.group({
  75 + entityIds: [null, [Validators.required]]
  76 + });
  77 + switch (this.data.entityType) {
  78 + case EntityType.DEVICE:
  79 + this.assignToEdgeTitle = 'device.assign-device-to-edge';
  80 + this.assignToEdgeText = 'device.assign-device-to-edge-text';
  81 + break;
  82 + case EntityType.RULE_CHAIN:
  83 + this.assignToEdgeTitle = 'rulechain.assign-rulechain-to-edge';
  84 + this.assignToEdgeText = 'rulechain.assign-rulechain-to-edge-text';
  85 + break;
  86 + case EntityType.ASSET:
  87 + this.assignToEdgeTitle = 'asset.assign-asset-to-edge';
  88 + this.assignToEdgeText = 'asset.assign-asset-to-edge-text';
  89 + break;
  90 + case EntityType.ENTITY_VIEW:
  91 + this.assignToEdgeTitle = 'entity-view.assign-entity-view-to-edge';
  92 + this.assignToEdgeText = 'entity-view.assign-entity-view-to-edge-text';
  93 + break;
  94 + case EntityType.DASHBOARD:
  95 + this.assignToEdgeTitle = 'dashboard.assign-dashboard-to-edge';
  96 + this.assignToEdgeText = 'dashboard.assign-dashboard-to-edge-text';
  97 + break;
  98 + }
  99 + }
  100 +
  101 + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
  102 + const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
  103 + const customErrorState = !!(control && control.invalid && this.submitted);
  104 + return originalErrorState || customErrorState;
  105 + }
  106 +
  107 + cancel(): void {
  108 + this.dialogRef.close(false);
  109 + }
  110 +
  111 + assign(): void {
  112 + this.submitted = true;
  113 + const entityIds: Array<string> = this.addEntitiesToEdgeFormGroup.get('entityIds').value;
  114 + const tasks: Observable<any>[] = [];
  115 + entityIds.forEach(
  116 + (entityId) => {
  117 + tasks.push(this.getAssignToEdgeTask(this.data.edgeId, entityId));
  118 + }
  119 + );
  120 + forkJoin(tasks).subscribe(
  121 + () => {
  122 + this.dialogRef.close(true);
  123 + }
  124 + );
  125 + }
  126 +
  127 + private getAssignToEdgeTask(edgeId: string, entityId: string): Observable<any> {
  128 + switch (this.data.entityType) {
  129 + case EntityType.DEVICE:
  130 + return this.deviceService.assignDeviceToEdge(edgeId, entityId);
  131 + case EntityType.ASSET:
  132 + return this.assetService.assignAssetToEdge(edgeId, entityId);
  133 + case EntityType.ENTITY_VIEW:
  134 + return this.entityViewService.assignEntityViewToEdge(edgeId, entityId);
  135 + case EntityType.DASHBOARD:
  136 + return this.dashboardService.assignDashboardToEdge(edgeId, entityId);
  137 + case EntityType.RULE_CHAIN:
  138 + return this.ruleChainService.assignRuleChainToEdge(edgeId, entityId);
  139 + }
  140 + }
  141 +
  142 +}
@@ -20,12 +20,14 @@ import { SharedModule } from '@app/shared/shared.module'; @@ -20,12 +20,14 @@ import { SharedModule } from '@app/shared/shared.module';
20 import { AssignToCustomerDialogComponent } from '@modules/home/dialogs/assign-to-customer-dialog.component'; 20 import { AssignToCustomerDialogComponent } from '@modules/home/dialogs/assign-to-customer-dialog.component';
21 import { AddEntitiesToCustomerDialogComponent } from '@modules/home/dialogs/add-entities-to-customer-dialog.component'; 21 import { AddEntitiesToCustomerDialogComponent } from '@modules/home/dialogs/add-entities-to-customer-dialog.component';
22 import { HomeDialogsService } from './home-dialogs.service'; 22 import { HomeDialogsService } from './home-dialogs.service';
  23 +import { AddEntitiesToEdgeDialogComponent } from "@home/dialogs/add-entities-to-edge-dialog.component";
23 24
24 @NgModule({ 25 @NgModule({
25 declarations: 26 declarations:
26 [ 27 [
27 AssignToCustomerDialogComponent, 28 AssignToCustomerDialogComponent,
28 - AddEntitiesToCustomerDialogComponent 29 + AddEntitiesToCustomerDialogComponent,
  30 + AddEntitiesToEdgeDialogComponent
29 ], 31 ],
30 imports: [ 32 imports: [
31 CommonModule, 33 CommonModule,
@@ -33,7 +35,8 @@ import { HomeDialogsService } from './home-dialogs.service'; @@ -33,7 +35,8 @@ import { HomeDialogsService } from './home-dialogs.service';
33 ], 35 ],
34 exports: [ 36 exports: [
35 AssignToCustomerDialogComponent, 37 AssignToCustomerDialogComponent,
36 - AddEntitiesToCustomerDialogComponent 38 + AddEntitiesToCustomerDialogComponent,
  39 + AddEntitiesToEdgeDialogComponent
37 ], 40 ],
38 providers: [ 41 providers: [
39 HomeDialogsService 42 HomeDialogsService
@@ -58,6 +58,11 @@ import { AssetId } from '@app/shared/models/id/asset-id'; @@ -58,6 +58,11 @@ import { AssetId } from '@app/shared/models/id/asset-id';
58 import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component'; 58 import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component';
59 import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; 59 import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
60 import { DeviceInfo } from '@shared/models/device.models'; 60 import { DeviceInfo } from '@shared/models/device.models';
  61 +import { EdgeService } from "@core/http/edge.service";
  62 +import {
  63 + AddEntitiesToEdgeDialogComponent,
  64 + AddEntitiesToEdgeDialogData
  65 +} from "@home/dialogs/add-entities-to-edge-dialog.component";
61 66
62 @Injectable() 67 @Injectable()
63 export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> { 68 export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> {
@@ -65,11 +70,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -65,11 +70,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
65 private readonly config: EntityTableConfig<AssetInfo> = new EntityTableConfig<AssetInfo>(); 70 private readonly config: EntityTableConfig<AssetInfo> = new EntityTableConfig<AssetInfo>();
66 71
67 private customerId: string; 72 private customerId: string;
  73 + private edgeId: string;
68 74
69 constructor(private store: Store<AppState>, 75 constructor(private store: Store<AppState>,
70 private broadcast: BroadcastService, 76 private broadcast: BroadcastService,
71 private assetService: AssetService, 77 private assetService: AssetService,
72 private customerService: CustomerService, 78 private customerService: CustomerService,
  79 + private edgeService: EdgeService,
73 private dialogService: DialogService, 80 private dialogService: DialogService,
74 private homeDialogs: HomeDialogsService, 81 private homeDialogs: HomeDialogsService,
75 private translate: TranslateService, 82 private translate: TranslateService,
@@ -111,6 +118,7 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -111,6 +118,7 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
111 assetType: '' 118 assetType: ''
112 }; 119 };
113 this.customerId = routeParams.customerId; 120 this.customerId = routeParams.customerId;
  121 + this.edgeId = routeParams.edgeId;
114 return this.store.pipe(select(selectAuthUser), take(1)).pipe( 122 return this.store.pipe(select(selectAuthUser), take(1)).pipe(
115 tap((authUser) => { 123 tap((authUser) => {
116 if (authUser.authority === Authority.CUSTOMER_USER) { 124 if (authUser.authority === Authority.CUSTOMER_USER) {
@@ -128,7 +136,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -128,7 +136,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
128 } else { 136 } else {
129 this.config.tableTitle = parentCustomer.title + ': ' + this.translate.instant('asset.assets'); 137 this.config.tableTitle = parentCustomer.title + ': ' + this.translate.instant('asset.assets');
130 } 138 }
131 - } else { 139 + } else if (this.edgeId) { // TODO: deaflynx: find better way - out of parentCustomer map
  140 + this.edgeService.getEdge(this.edgeId)
  141 + .pipe(map(edge =>
  142 + this.config.tableTitle = edge.name + ': ' + this.translate.instant('asset.assets') ),
  143 + ).subscribe();
  144 + }
  145 + else {
132 this.config.tableTitle = this.translate.instant('asset.assets'); 146 this.config.tableTitle = this.translate.instant('asset.assets');
133 } 147 }
134 this.config.columns = this.configureColumns(this.config.componentsData.assetScope); 148 this.config.columns = this.configureColumns(this.config.componentsData.assetScope);
@@ -168,6 +182,10 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -168,6 +182,10 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
168 this.config.entitiesFetchFunction = pageLink => 182 this.config.entitiesFetchFunction = pageLink =>
169 this.assetService.getTenantAssetInfos(pageLink, this.config.componentsData.assetType); 183 this.assetService.getTenantAssetInfos(pageLink, this.config.componentsData.assetType);
170 this.config.deleteEntity = id => this.assetService.deleteAsset(id.id); 184 this.config.deleteEntity = id => this.assetService.deleteAsset(id.id);
  185 + } else if (assetScope === 'edge') {
  186 + this.config.entitiesFetchFunction = pageLink =>
  187 + this.assetService.getEdgeAssets(this.edgeId, pageLink, this.config.componentsData.assetType);
  188 + this.config.deleteEntity = id => this.assetService.deleteAsset(id.id);
171 } else { 189 } else {
172 this.config.entitiesFetchFunction = pageLink => 190 this.config.entitiesFetchFunction = pageLink =>
173 this.assetService.getCustomerAssetInfos(this.customerId, pageLink, this.config.componentsData.assetType); 191 this.assetService.getCustomerAssetInfos(this.customerId, pageLink, this.config.componentsData.assetType);
@@ -221,6 +239,16 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -221,6 +239,16 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
221 } 239 }
222 ); 240 );
223 } 241 }
  242 + if (assetScope === 'edge') {
  243 + actions.push(
  244 + {
  245 + name: this.translate.instant('asset.unassign-from-edge'),
  246 + icon: 'portable_wifi_off',
  247 + isEnabled: (entity) => (entity.edgeId && entity.edgeId.id !== NULL_UUID),
  248 + onAction: ($event, entity) => this.unassignFromEdge($event, entity)
  249 + }
  250 + );
  251 + }
224 return actions; 252 return actions;
225 } 253 }
226 254
@@ -236,6 +264,16 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -236,6 +264,16 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
236 } 264 }
237 ); 265 );
238 } 266 }
  267 + if (assetScope === 'edge') {
  268 + actions.push(
  269 + {
  270 + name: this.translate.instant('asset.unassign-assets-from-edge'),
  271 + icon: 'portable_wifi_off',
  272 + isEnabled: true,
  273 + onAction: ($event, entities) => this.unassignAssetsFromEdge($event, entities)
  274 + }
  275 + );
  276 + }
239 if (assetScope === 'customer') { 277 if (assetScope === 'customer') {
240 actions.push( 278 actions.push(
241 { 279 {
@@ -277,6 +315,16 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -277,6 +315,16 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
277 } 315 }
278 ); 316 );
279 } 317 }
  318 + if (assetScope === 'edge') {
  319 + actions.push(
  320 + {
  321 + name: this.translate.instant('asset.assign-new-asset'),
  322 + icon: 'add',
  323 + isEnabled: () => true,
  324 + onAction: ($event) => this.addAssetsToEdge($event)
  325 + }
  326 + );
  327 + }
280 return actions; 328 return actions;
281 } 329 }
282 330
@@ -309,6 +357,26 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -309,6 +357,26 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
309 }); 357 });
310 } 358 }
311 359
  360 + addAssetsToEdge($event: Event) {
  361 + if ($event) {
  362 + $event.stopPropagation();
  363 + }
  364 + this.dialog.open<AddEntitiesToEdgeDialogComponent, AddEntitiesToEdgeDialogData,
  365 + boolean>(AddEntitiesToEdgeDialogComponent, {
  366 + disableClose: true,
  367 + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
  368 + data: {
  369 + edgeId: this.edgeId,
  370 + entityType: EntityType.ASSET
  371 + }
  372 + }).afterClosed()
  373 + .subscribe((res) => {
  374 + if (res) {
  375 + this.config.table.updateData();
  376 + }
  377 + });
  378 + }
  379 +
312 makePublic($event: Event, asset: Asset) { 380 makePublic($event: Event, asset: Asset) {
313 if ($event) { 381 if ($event) {
314 $event.stopPropagation(); 382 $event.stopPropagation();
@@ -426,4 +494,54 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse @@ -426,4 +494,54 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
426 return false; 494 return false;
427 } 495 }
428 496
  497 + unassignFromEdge($event: Event, asset: AssetInfo) {
  498 + if ($event) {
  499 + $event.stopPropagation();
  500 + }
  501 + this.dialogService.confirm(
  502 + this.translate.instant('asset.unassign-asset-from-edge-title', {assetName: asset.name}),
  503 + this.translate.instant('asset.unassign-asset-from-edge-text'),
  504 + this.translate.instant('action.no'),
  505 + this.translate.instant('action.yes'),
  506 + true
  507 + ).subscribe((res) => {
  508 + if (res) {
  509 + this.assetService.unassignAssetFromEdge(asset.id.id).subscribe(
  510 + () => {
  511 + this.config.table.updateData();
  512 + }
  513 + );
  514 + }
  515 + }
  516 + );
  517 + }
  518 +
  519 + unassignAssetsFromEdge($event: Event, assets: Array<AssetInfo>) {
  520 + if ($event) {
  521 + $event.stopPropagation();
  522 + }
  523 + this.dialogService.confirm(
  524 + this.translate.instant('asset.unassign-assets-from-edge-title', {count: assets.length}),
  525 + this.translate.instant('asset.unassign-assets-from-edge-text'),
  526 + this.translate.instant('action.no'),
  527 + this.translate.instant('action.yes'),
  528 + true
  529 + ).subscribe((res) => {
  530 + if (res) {
  531 + const tasks: Observable<any>[] = [];
  532 + assets.forEach(
  533 + (asset) => {
  534 + tasks.push(this.assetService.unassignAssetFromEdge(asset.id.id));
  535 + }
  536 + );
  537 + forkJoin(tasks).subscribe(
  538 + () => {
  539 + this.config.table.updateData();
  540 + }
  541 + );
  542 + }
  543 + }
  544 + );
  545 + }
  546 +
429 } 547 }
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { NgModule } from '@angular/core';
  18 +import { RouterModule, Routes } from "@angular/router";
  19 +import { EntitiesTableComponent } from "@home/components/entity/entities-table.component";
  20 +import { Authority } from "@shared/models/authority.enum";
  21 +import { EdgesTableConfigResolver } from "@home/pages/edge/edges-table-config.resolver"
  22 +import { AssetsTableConfigResolver } from "@home/pages/asset/assets-table-config.resolver";
  23 +import { DevicesTableConfigResolver } from "@home/pages/device/devices-table-config.resolver";
  24 +import { EntityViewsTableConfigResolver } from "@home/pages/entity-view/entity-views-table-config.resolver";
  25 +import { DashboardsTableConfigResolver } from "@home/pages/dashboard/dashboards-table-config.resolver";
  26 +import { RuleChainsTableConfigResolver } from "@home/pages/rulechain/rulechains-table-config.resolver";
  27 +
  28 +const routes: Routes = [
  29 + {
  30 + path: 'edges',
  31 + data: {
  32 + breadcrumb: {
  33 + label: 'edge.edges',
  34 + icon: 'router'
  35 + }
  36 + },
  37 + children: [
  38 + {
  39 + path: '',
  40 + component: EntitiesTableComponent,
  41 + data: {
  42 + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
  43 + title: 'edge.edges',
  44 + edgeScope: 'tenant'
  45 + },
  46 + resolve: {
  47 + entitiesTableConfig: EdgesTableConfigResolver
  48 + }
  49 + },
  50 + {
  51 + path: ':edgeId/ruleChains',
  52 + component: EntitiesTableComponent,
  53 + data: {
  54 + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
  55 + title: 'edge.rulechains',
  56 + ruleChainScope: 'edge',
  57 + breadcrumb: {
  58 + label: 'edge.rulechains',
  59 + icon: 'settings_ethernet'
  60 + },
  61 + },
  62 + resolve: {
  63 + entitiesTableConfig: RuleChainsTableConfigResolver
  64 + }
  65 + },
  66 + {
  67 + path: ':edgeId/assets',
  68 + component: EntitiesTableComponent,
  69 + data: {
  70 + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
  71 + title: 'edge.assets',
  72 + assetsType: 'edge',
  73 + breadcrumb: {
  74 + label: 'edge.assets',
  75 + icon: 'domain'
  76 + }
  77 + },
  78 + resolve: {
  79 + entitiesTableConfig: AssetsTableConfigResolver
  80 + }
  81 + },
  82 + {
  83 + path: ':edgeId/devices',
  84 + component: EntitiesTableComponent,
  85 + data: {
  86 + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
  87 + title: 'edge.devices',
  88 + devicesType: 'edge',
  89 + breadcrumb: {
  90 + label: 'edge.devices',
  91 + icon: 'devices_other'
  92 + }
  93 + },
  94 + resolve: {
  95 + entitiesTableConfig: DevicesTableConfigResolver
  96 + }
  97 + },
  98 + {
  99 + path: ':edgeId/entityViews',
  100 + component: EntitiesTableComponent,
  101 + data: {
  102 + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
  103 + title: 'edge.entity-views',
  104 + entityViewsType: 'edge',
  105 + breadcrumb: {
  106 + label: 'edge.entity-views',
  107 + icon: 'view_quilt'
  108 + },
  109 + },
  110 + resolve: {
  111 + entitiesTableConfig: EntityViewsTableConfigResolver
  112 + }
  113 + },
  114 + {
  115 + path: ':edgeId/dashboards',
  116 + component: EntitiesTableComponent,
  117 + data: {
  118 + auth: [Authority.TENANT_ADMIN, Authority.CUSTOMER_USER],
  119 + title: 'edge.dashboards',
  120 + dashboardsType: 'edge',
  121 + breadcrumb: {
  122 + label: 'edge.dashboards',
  123 + icon: 'dashboard'
  124 + }
  125 + },
  126 + resolve: {
  127 + entitiesTableConfig: DashboardsTableConfigResolver
  128 + }
  129 + }]
  130 + }]
  131 +
  132 +@NgModule({
  133 + imports: [RouterModule.forChild(routes)],
  134 + exports: [RouterModule],
  135 + providers: [
  136 + EdgesTableConfigResolver
  137 + ]
  138 +})
  139 +export class EdgeRoutingModule { }
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<tb-entity-subtype-select
  19 + [showLabel]="true"
  20 + [entityType]="entityType.EDGE"
  21 + [ngModel]="entitiesTableConfig.componentsData.edgeType"
  22 + (ngModelChange)="edgeTypeChanged($event)">
  23 +</tb-entity-subtype-select>
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +@import '../../../../../scss/constants';
  17 +
  18 +:host {
  19 + flex: 1;
  20 + display: flex;
  21 + justify-content: flex-start;
  22 + min-width: 150px;
  23 +}
  24 +
  25 +:host ::ng-deep {
  26 + tb-entity-subtype-select {
  27 + width: 100%;
  28 +
  29 + mat-form-field {
  30 + font-size: 16px;
  31 +
  32 + .mat-form-field-wrapper {
  33 + padding-bottom: 0;
  34 + }
  35 +
  36 + .mat-form-field-underline {
  37 + bottom: 0;
  38 + }
  39 +
  40 + @media #{$mat-xs} {
  41 + width: 100%;
  42 +
  43 + .mat-form-field-infix {
  44 + width: auto !important;
  45 + }
  46 + }
  47 + }
  48 + }
  49 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Component } from '@angular/core';
  18 +import { EntityTableHeaderComponent } from "@home/components/entity/entity-table-header.component";
  19 +import { EntityType } from "@shared/models/entity-type.models";
  20 +import { Store } from "@ngrx/store";
  21 +import { AppState } from "@core/core.state";
  22 +import { EdgeInfo } from "@shared/models/edge.models";
  23 +
  24 +@Component({
  25 + selector: 'tb-edge-table-header',
  26 + templateUrl: './edge-table-header.component.html',
  27 + styleUrls: ['./edge-table-header.component.scss']
  28 +})
  29 +export class EdgeTableHeaderComponent extends EntityTableHeaderComponent<EdgeInfo> {
  30 +
  31 + entityType = EntityType;
  32 +
  33 + constructor(protected store: Store<AppState>) {
  34 + super(store);
  35 + }
  36 +
  37 + edgeTypeChanged(edgeType: string) {
  38 + this.entitiesTableConfig.componentsData.edgeType = edgeType;
  39 + this.entitiesTableConfig.table.resetSortAndFilter(true);
  40 + }
  41 +
  42 +}
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<mat-tab *ngIf="entity"
  19 + label="{{ 'attribute.attributes' | translate }}" #attributesTab="matTab">
  20 + <tb-attribute-table [defaultAttributeScope]="attributeScopes.CLIENT_SCOPE"
  21 + [active]="attributesTab.isActive"
  22 + [entityId]="entity.id"
  23 + [entityName]="entity.name">
  24 + </tb-attribute-table>
  25 +</mat-tab>
  26 +<mat-tab *ngIf="entity"
  27 + label="{{ 'attribute.latest-telemetry' | translate }}" #telemetryTab="matTab">
  28 + <tb-attribute-table [defaultAttributeScope]="latestTelemetryTypes.LATEST_TELEMETRY"
  29 + disableAttributeScopeSelection
  30 + [active]="telemetryTab.isActive"
  31 + [entityId]="entity.id"
  32 + [entityName]="entity.name">
  33 + </tb-attribute-table>
  34 +</mat-tab>
  35 +<mat-tab *ngIf="entity"
  36 + label="{{ 'alarm.alarms' | translate }}" #alarmsTab="matTab">
  37 + <tb-alarm-table [active]="alarmsTab.isActive" [entityId]="entity.id"></tb-alarm-table>
  38 +</mat-tab>
  39 +<mat-tab *ngIf="entity"
  40 + label="{{ 'edge.events' | translate }}" #eventsTab="matTab">
  41 + <tb-event-table [defaultEventType]="eventTypes.ERROR" [active]="eventsTab.isActive" [tenantId]="entity.tenantId.id"
  42 + [entityId]="entity.id"></tb-event-table>
  43 +</mat-tab>
  44 +<mat-tab *ngIf="entity"
  45 + label="{{ 'relation.relations' | translate }}" #relationsTab="matTab">
  46 + <tb-relation-table [active]="relationsTab.isActive" [entityId]="entity.id"></tb-relation-table>
  47 +</mat-tab>
  48 +<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
  49 + label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
  50 + <tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
  51 +</mat-tab>
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import {Component} from '@angular/core';
  18 +import {Store} from "@ngrx/store";
  19 +import {AppState} from "@core/core.state";
  20 +import {EdgeInfo} from "@shared/models/edge.models";
  21 +import {EntityTabsComponent} from "@home/components/entity/entity-tabs.component";
  22 +
  23 +@Component({
  24 + selector: 'tb-edge-tabs',
  25 + templateUrl: './edge-tabs.component.html',
  26 + styleUrls: []
  27 +})
  28 +export class EdgeTabsComponent extends EntityTabsComponent<EdgeInfo> {
  29 +
  30 + constructor(protected store: Store<AppState>) {
  31 + super(store);
  32 + }
  33 +
  34 + ngOnInit() {
  35 + super.ngOnInit();
  36 + }
  37 +
  38 +}
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div class="tb-details-buttons" fxLayout.xs="column">
  19 + <button mat-raised-button color="primary"
  20 + [disabled]="(isLoading$ | async)"
  21 + (click)="onEntityAction($event, 'makePublic')"
  22 + [fxShow]="!isEdit && edgeScope === 'tenant' && !isAssignedToCustomer(entity) && !entity?.customerIsPublic">
  23 + {{'edge.make-public' | translate }}
  24 + </button>
  25 + <button mat-raised-button color="primary"
  26 + [disabled]="(isLoading$ | async)"
  27 + (click)="onEntityAction($event, 'assignToCustomer')"
  28 + [fxShow]="!isEdit && edgeScope === 'tenant' && !isAssignedToCustomer(entity)">
  29 + {{'edge.assign-to-customer' | translate }}
  30 + </button>
  31 + <button mat-raised-button color="primary"
  32 + [disabled]="(isLoading$ | async)"
  33 + (click)="onEntityAction($event, 'unassignFromCustomer')"
  34 + [fxShow]="!isEdit && (edgeScope === 'customer' || edgeScope === 'tenant') && isAssignedToCustomer(entity)">
  35 + {{ (entity?.customerIsPublic ? 'edge.make-private' : 'edge.unassign-from-customer') | translate }}
  36 + </button>
  37 + <button mat-raised-button color="primary" fxFlex.xs
  38 + [disabled]="(isLoading$ | async)"
  39 + (click)="onEntityAction($event, 'delete')"
  40 + [fxShow]="!hideDelete() && !isEdit">
  41 + {{'edge.delete' | translate }}
  42 + </button>
  43 + <div fxLayout="row" fxLayout.xs="column">
  44 + <button mat-raised-button
  45 + ngxClipboard
  46 + (cbOnSuccess)="onEdgeIdCopied($event)"
  47 + [cbContent]="entity?.id?.id"
  48 + [fxShow]="!isEdit">
  49 + <mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
  50 + <span translate>edge.copy-id</span>
  51 + </button>
  52 + </div>
  53 +</div>
  54 +<div class="mat-padding" fxLayout="column">
  55 + <mat-form-field class="mat-block"
  56 + [fxShow]="!isEdit && isAssignedToCustomer(entity)
  57 + && !entity?.customerIsPublic && edgeScope === 'tenant'">
  58 + <mat-label translate>edge.assigned-to-customer</mat-label>
  59 + <input matInput disabled [ngModel]="entity?.customerTitle">
  60 + </mat-form-field>
  61 + <div class="tb-small" style="padding-bottom: 10px; padding-left: 2px;"
  62 + [fxShow]="!isEdit && entity?.customerIsPublic && (edgeScope === 'customer' || edgeScope === 'tenant')">
  63 + {{ 'edge.public' | translate }}
  64 + </div>
  65 + <form [formGroup]="entityForm">
  66 + <fieldset [disabled]="(isLoading$ | async) || !isEdit">
  67 + <mat-form-field class="mat-block">
  68 + <mat-label translate>edge.name</mat-label>
  69 + <input matInput formControlName="name" required>
  70 + <mat-error *ngIf="entityForm.get('name').hasError('required')">
  71 + {{ 'edge.name-required' | translate }}
  72 + </mat-error>
  73 + </mat-form-field>
  74 + <tb-entity-subtype-autocomplete
  75 + formControlName="type"
  76 + [required]="true"
  77 + [entityType]="entityType.EDGE">
  78 + </tb-entity-subtype-autocomplete>
  79 + <mat-form-field class="mat-block">
  80 + <mat-label translate>edge.label</mat-label>
  81 + <input matInput formControlName="label">
  82 + </mat-form-field>
  83 +
  84 + <div formGroupName="additionalInfo" fxLayout="column">
  85 + <mat-form-field class="mat-block">
  86 + <mat-label translate>edge.description</mat-label>
  87 + <textarea matInput formControlName="description" rows="2"></textarea>
  88 + </mat-form-field>
  89 + </div>
  90 + </fieldset>
  91 + <div fxLayout="row">
  92 + <fieldset fxFlex disabled>
  93 + <mat-form-field class="mat-block">
  94 + <mat-label translate>edge.edge-key</mat-label>
  95 + <input matInput formControlName="routingKey">
  96 + </mat-form-field>
  97 + </fieldset>
  98 + <button mat-button mat-icon-button
  99 + style="margin-top: 14px"
  100 + ngxClipboard
  101 + (cbOnSuccess)="onEdgeKeyCopied($event)"
  102 + [cbContent]="entity?.routingKey"
  103 + [fxShow]="!isEdit">
  104 + <mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
  105 + </button>
  106 + </div>
  107 + <div fxLayout="row">
  108 + <fieldset fxFlex disabled>
  109 + <mat-form-field class="mat-block">
  110 + <mat-label translate>edge.edge-secret</mat-label>
  111 + <input matInput formControlName="secret">
  112 + </mat-form-field>
  113 + </fieldset>
  114 + <button mat-button mat-icon-button
  115 + style="margin-top: 14px"
  116 + ngxClipboard
  117 + (cbOnSuccess)="onEdgeSecretCopied($event)"
  118 + [cbContent]="entity?.secret"
  119 + [fxShow]="!isEdit">
  120 + <mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
  121 + </button>
  122 + </div>
  123 + </form>
  124 +</div>
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +:host {
  17 +
  18 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Component, Inject } from '@angular/core';
  18 +import { Store } from '@ngrx/store';
  19 +import { AppState } from "@core/core.state";
  20 +import { EntityComponent } from "@home/components/entity/entity.component";
  21 +import {FormBuilder, FormControl, FormGroup, NgModel, Validators} from "@angular/forms";
  22 +import { EntityType } from "@shared/models/entity-type.models";
  23 +import { EdgeInfo } from "@shared/models/edge.models";
  24 +import { TranslateService } from "@ngx-translate/core";
  25 +import { NULL_UUID } from "@shared/models/id/has-uuid";
  26 +import { ActionNotificationShow } from "@core/notification/notification.actions";
  27 +import { guid, isUndefined } from "@core/utils";
  28 +import { EntityTableConfig } from "@home/models/entity/entities-table-config.models";
  29 +
  30 +@Component({
  31 + selector: 'tb-edge',
  32 + templateUrl: './edge.component.html',
  33 + styleUrls: ['./edge.component.scss']
  34 +})
  35 +
  36 +export class EdgeComponent extends EntityComponent<EdgeInfo>{
  37 +
  38 + entityType = EntityType;
  39 + edgeScope: 'tenant' | 'customer' | 'customer_user';
  40 +
  41 + constructor(protected store: Store<AppState>,
  42 + protected translate: TranslateService,
  43 + @Inject('entity') protected entityValue: EdgeInfo,
  44 + @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<EdgeInfo>,
  45 + public fb: FormBuilder) {
  46 + super(store, fb, entityValue, entitiesTableConfigValue);
  47 + }
  48 +
  49 + ngOnInit() {
  50 + this.edgeScope = this.entitiesTableConfig.componentsData.edgeScope;
  51 + super.ngOnInit()
  52 + }
  53 +
  54 + hideDelete() {
  55 + if (this.entitiesTableConfig) {
  56 + return !this.entitiesTableConfig.deleteEnabled(this.entity);
  57 + } else {
  58 + return false;
  59 + }
  60 + }
  61 +
  62 + isAssignedToCustomer(entity: EdgeInfo): boolean {
  63 + return entity && entity.customerId && entity.customerId.id !== NULL_UUID;
  64 + }
  65 +
  66 + buildForm(entity: EdgeInfo): FormGroup {
  67 + return this.fb.group(
  68 + {
  69 + name: [entity ? entity.name : '', [Validators.required]],
  70 + type: [entity ? entity.type : null, [Validators.required]],
  71 + label: [entity ? entity.label : ''],
  72 + routingKey: guid(),
  73 + secret: this.generateSecret(20),
  74 + additionalInfo: this.fb.group(
  75 + {
  76 + description: [entity && entity.additionalInfo ? entity.additionalInfo.description : '']
  77 + }
  78 + )
  79 + }
  80 + );
  81 + }
  82 +
  83 + updateForm(entity: EdgeInfo) {
  84 + this.entityForm.patchValue({name: entity.name});
  85 + this.entityForm.patchValue({type: entity.type});
  86 + this.entityForm.patchValue({label: entity.label});
  87 + this.entityForm.patchValue({routingKey: entity.routingKey});
  88 + this.entityForm.patchValue({secret: entity.secret});
  89 + this.entityForm.patchValue({additionalInfo: {
  90 + description: entity.additionalInfo ? entity.additionalInfo.description : ''}});
  91 + }
  92 +
  93 + onEdgeIdCopied($event) {
  94 + this.store.dispatch(new ActionNotificationShow(
  95 + {
  96 + message: this.translate.instant('edge.id-copied-message'),
  97 + type: 'success',
  98 + duration: 750,
  99 + verticalPosition: 'bottom',
  100 + horizontalPosition: 'left'
  101 + }));
  102 + }
  103 +
  104 + onEdgeKeyCopied($event) {
  105 + this.store.dispatch(new ActionNotificationShow(
  106 + {
  107 + message: this.translate.instant('edge.edge-key-copied-message'),
  108 + type: 'success',
  109 + duration: 750,
  110 + verticalPosition: 'bottom',
  111 + horizontalPosition: 'left'
  112 + }));
  113 + }
  114 +
  115 + onEdgeSecretCopied($event) {
  116 + this.store.dispatch(new ActionNotificationShow(
  117 + {
  118 + message: this.translate.instant('edge.edge-secret-copied-message'),
  119 + type: 'success',
  120 + duration: 750,
  121 + verticalPosition: 'bottom',
  122 + horizontalPosition: 'left'
  123 + }));
  124 + }
  125 +
  126 + generateSecret(length): string {
  127 + if (isUndefined(length) || length == null) {
  128 + length = 1;
  129 + }
  130 + var l = length > 10 ? 10 : length;
  131 + var str = Math.random().toString(36).substr(2, l);
  132 + if (str.length >= length) {
  133 + return str;
  134 + }
  135 + return str.concat(this.generateSecret(length - str.length));
  136 + }
  137 +
  138 +}
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { NgModule } from '@angular/core';
  18 +import { CommonModule } from '@angular/common';
  19 +import { SharedModule } from '@shared/shared.module';
  20 +import { HomeDialogsModule } from "@home/dialogs/home-dialogs.module";
  21 +import { HomeComponentsModule } from "@home/components/home-components.module";
  22 +import { EdgeRoutingModule } from "@home/pages/edge/edge-routing.module";
  23 +import { EdgeComponent } from '@modules/home/pages/edge/edge.component';
  24 +import { EdgeTableHeaderComponent } from "@home/pages/edge/edge-table-header.component";
  25 +import { EdgeTabsComponent } from "@home/pages/edge/edge-tabs.component";
  26 +
  27 +@NgModule({
  28 + declarations: [
  29 + EdgeComponent,
  30 + EdgeTableHeaderComponent,
  31 + EdgeTabsComponent
  32 + ],
  33 + imports: [
  34 + CommonModule,
  35 + SharedModule,
  36 + HomeDialogsModule,
  37 + HomeComponentsModule,
  38 + EdgeRoutingModule
  39 + ]
  40 +})
  41 +
  42 +export class EdgeModule { }
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { Injectable } from '@angular/core';
  18 +
  19 +import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
  20 +import {
  21 + CellActionDescriptor,
  22 + checkBoxCell,
  23 + DateEntityTableColumn,
  24 + EntityTableColumn,
  25 + EntityTableConfig,
  26 + GroupActionDescriptor,
  27 + HeaderActionDescriptor
  28 +} from '@home/models/entity/entities-table-config.models';
  29 +import { TranslateService } from '@ngx-translate/core';
  30 +import { DatePipe } from '@angular/common';
  31 +import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
  32 +import { EntityAction } from '@home/models/entity/entity-component.models';
  33 +import { forkJoin, Observable, of } from 'rxjs';
  34 +import { select, Store } from '@ngrx/store';
  35 +import { selectAuthUser } from '@core/auth/auth.selectors';
  36 +import { map, mergeMap, take, tap } from 'rxjs/operators';
  37 +import { AppState } from '@core/core.state';
  38 +import { Authority } from '@app/shared/models/authority.enum';
  39 +import { CustomerService } from '@core/http/customer.service';
  40 +import { Customer } from '@app/shared/models/customer.model';
  41 +import { NULL_UUID } from '@shared/models/id/has-uuid';
  42 +import { BroadcastService } from '@core/services/broadcast.service';
  43 +import { MatDialog } from '@angular/material/dialog';
  44 +import { DialogService } from '@core/services/dialog.service';
  45 +import {
  46 + AssignToCustomerDialogComponent,
  47 + AssignToCustomerDialogData
  48 +} from '@modules/home/dialogs/assign-to-customer-dialog.component';
  49 +import {
  50 + AddEntitiesToCustomerDialogComponent,
  51 + AddEntitiesToCustomerDialogData
  52 +} from '../../dialogs/add-entities-to-customer-dialog.component';
  53 +import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
  54 +
  55 +import { Edge, EdgeInfo } from "@shared/models/edge.models";
  56 +import { EdgeService } from "@core/http/edge.service";
  57 +import { EdgeComponent } from "@home/pages/edge/edge.component";
  58 +import { EdgeTableHeaderComponent } from "@home/pages/edge/edge-table-header.component";
  59 +import { EdgeId } from "@shared/models/id/edge-id";
  60 +import { EdgeTabsComponent } from "@home/pages/edge/edge-tabs.component";
  61 +
  62 +@Injectable()
  63 +export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeInfo>> {
  64 +
  65 + private readonly config: EntityTableConfig<EdgeInfo> = new EntityTableConfig<EdgeInfo>();
  66 + private customerId: string;
  67 +
  68 + constructor(private store: Store<AppState>,
  69 + private broadcast: BroadcastService,
  70 + private edgeService: EdgeService,
  71 + private customerService: CustomerService,
  72 + private dialogService: DialogService,
  73 + private homeDialogs: HomeDialogsService,
  74 + private translate: TranslateService,
  75 + private datePipe: DatePipe,
  76 + private router: Router,
  77 + private dialog: MatDialog) {
  78 +
  79 + this.config.entityType = EntityType.EDGE;
  80 + this.config.entityComponent = EdgeComponent;
  81 + this.config.entityTabsComponent = EdgeTabsComponent;
  82 + this.config.entityTranslations = entityTypeTranslations.get(EntityType.EDGE);
  83 + this.config.entityResources = entityTypeResources.get(EntityType.EDGE);
  84 +
  85 + this.config.deleteEntityTitle = edge => this.translate.instant('edge.delete-edge-title', {edgeName: edge.name});
  86 + this.config.deleteEntityContent = () => this.translate.instant('edge.delete-edge-text');
  87 + this.config.deleteEntitiesTitle = count => this.translate.instant('edge.delete-edges-title', {count});
  88 + this.config.deleteEntitiesContent = () => this.translate.instant('edge.delete-edges-text');
  89 +
  90 + this.config.loadEntity = id => this.edgeService.getEdge(id.id);
  91 + this.config.saveEntity = edge => {
  92 + return this.edgeService.saveEdge(edge).pipe(
  93 + tap(() => {
  94 + this.broadcast.broadcast('edgeSaved');
  95 + }),
  96 + mergeMap((savedEdge) => this.edgeService.getEdge(savedEdge.id.id)
  97 + ));
  98 + };
  99 +
  100 + this.config.onEntityAction = action => this.onEdgeAction(action);
  101 + this.config.detailsReadonly = () => this.config.componentsData.edgeScope === 'customer_user';
  102 +
  103 + this.config.headerComponent = EdgeTableHeaderComponent;
  104 +
  105 + }
  106 +
  107 + resolve(route: ActivatedRouteSnapshot): Observable<EntityTableConfig<EdgeInfo>> {
  108 + const routeParams = route.params;
  109 + this.config.componentsData = {
  110 + edgeScope: route.data.edgeScope,
  111 + edgeType: ''
  112 + };
  113 + this.customerId = routeParams.customerId;
  114 + return this.store.pipe(select(selectAuthUser), take(1)).pipe(
  115 + tap((authUser) => {
  116 + if (authUser.authority === Authority.CUSTOMER_USER) {
  117 + this.config.componentsData.edgeScope = 'customer_user';
  118 + this.customerId = authUser.customerId;
  119 + }
  120 + }),
  121 + mergeMap(() =>
  122 + this.customerId ? this.customerService.getCustomer(this.customerId) : of(null as Customer)
  123 + ),
  124 + map((parentCustomer) => {
  125 + if (parentCustomer) {
  126 + if (parentCustomer.additionalInfo && parentCustomer.additionalInfo.isPublic) {
  127 + this.config.tableTitle = this.translate.instant('customer.public-edges');
  128 + } else {
  129 + this.config.tableTitle = parentCustomer.title + ': ' + this.translate.instant('edge.edges');
  130 + }
  131 + } else {
  132 + this.config.tableTitle = this.translate.instant('edge.edges');
  133 + }
  134 + this.config.columns = this.configureColumns(this.config.componentsData.edgeScope);
  135 + this.configureEntityFunctions(this.config.componentsData.edgeScope);
  136 + this.config.cellActionDescriptors = this.configureCellActions(this.config.componentsData.edgeScope);
  137 + this.config.groupActionDescriptors = this.configureGroupActions(this.config.componentsData.edgeScope);
  138 + this.config.addActionDescriptors = this.configureAddActions(this.config.componentsData.edgeScope);
  139 + this.config.addEnabled = this.config.componentsData.edgeScope !== 'customer_user';
  140 + this.config.entitiesDeleteEnabled = this.config.componentsData.edgeScope === 'tenant';
  141 + this.config.deleteEnabled = () => this.config.componentsData.edgeScope === 'tenant';
  142 + return this.config;
  143 + })
  144 + );
  145 + }
  146 +
  147 + configureColumns(edgeScope: string): Array<EntityTableColumn<EdgeInfo>> {
  148 + const columns: Array<EntityTableColumn<EdgeInfo>> = [
  149 + new DateEntityTableColumn<EdgeInfo>('createdTime', 'common.created-time', this.datePipe, '150px'),
  150 + new EntityTableColumn<EdgeInfo>('name', 'edge.name', '25%'),
  151 + new EntityTableColumn<EdgeInfo>('type', 'edge.edge-type', '25%'),
  152 + new EntityTableColumn<EdgeInfo>('label', 'edge.label', '25%')
  153 + ];
  154 + if (edgeScope === 'tenant') {
  155 + columns.push(
  156 + new EntityTableColumn<EdgeInfo>('customerTitle', 'customer.customer', '25%'),
  157 + new EntityTableColumn<EdgeInfo>('customerIsPublic', 'edge.public', '60px',
  158 + entity => {
  159 + return checkBoxCell(entity.customerIsPublic);
  160 + }, () => ({}), false),
  161 + );
  162 + }
  163 + return columns;
  164 + }
  165 +
  166 + configureEntityFunctions(edgeScope: string): void {
  167 + if (edgeScope === 'tenant') {
  168 + this.config.entitiesFetchFunction = pageLink =>
  169 + this.edgeService.getTenantEdgeInfos(pageLink, this.config.componentsData.edgeType);
  170 + this.config.deleteEntity = id => this.edgeService.deleteEdge(id.id);
  171 + }
  172 + if (edgeScope === 'customer') {
  173 + this.config.entitiesFetchFunction = pageLink =>
  174 + this.edgeService.getCustomerEdges(this.customerId, pageLink, this.config.componentsData.edgeType);
  175 + this.config.deleteEntity = id => this.edgeService.unassignEdgeFromCustomer(id.id);
  176 + }
  177 + }
  178 +
  179 + configureCellActions(edgeScope: string): Array<CellActionDescriptor<EdgeInfo>> {
  180 + const actions: Array<CellActionDescriptor<EdgeInfo>> = [];
  181 + if (edgeScope === 'tenant') {
  182 + actions.push(
  183 + {
  184 + name: this.translate.instant('edge.make-public'),
  185 + icon: 'share',
  186 + isEnabled: (entity) => (!entity.customerId || entity.customerId.id === NULL_UUID),
  187 + onAction: ($event, entity) => this.makePublic($event, entity)
  188 + },
  189 + {
  190 + name: this.translate.instant('edge.assign-to-customer'),
  191 + icon: 'assignment_ind',
  192 + isEnabled: (entity) => (!entity.customerId || entity.customerId.id === NULL_UUID),
  193 + onAction: ($event, entity) => this.assignToCustomer($event, [entity.id])
  194 + },
  195 + {
  196 + name: this.translate.instant('edge.unassign-from-customer'),
  197 + icon: 'assignment_return',
  198 + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && !entity.customerIsPublic),
  199 + onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
  200 + },
  201 + {
  202 + name: this.translate.instant('edge.make-private'),
  203 + icon: 'reply',
  204 + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && entity.customerIsPublic),
  205 + onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
  206 + },
  207 + {
  208 + name: this.translate.instant('edge.manage-edge-assets'),
  209 + icon: 'domain',
  210 + isEnabled: (entity) => true,
  211 + onAction: ($event, entity) => this.openEdgeAssets($event, entity)
  212 + },
  213 + {
  214 + name: this.translate.instant('edge.manage-edge-devices'),
  215 + icon: 'devices_other',
  216 + isEnabled: (entity) => true,
  217 + onAction: ($event, entity) => this.openEdgeDevices($event, entity)
  218 + },
  219 + {
  220 + name: this.translate.instant('edge.manage-edge-entity-views'),
  221 + icon: 'view_quilt',
  222 + isEnabled: (entity) => true,
  223 + onAction: ($event, entity) => this.openEdgeEntityViews($event, entity)
  224 + },
  225 + {
  226 + name: this.translate.instant('edge.manage-edge-dashboards'),
  227 + icon: 'dashboard',
  228 + isEnabled: (entity) => true,
  229 + onAction: ($event, entity) => this.openEdgeDashboards($event, entity)
  230 + },
  231 + {
  232 + name: this.translate.instant('edge.manage-edge-rulechains'),
  233 + icon: 'settings_ethernet',
  234 + isEnabled: (entity) => true,
  235 + onAction: ($event, entity) => this.openEdgeRuleChains($event, entity)
  236 + }
  237 + );
  238 + }
  239 + if (edgeScope === 'customer') {
  240 + actions.push(
  241 + {
  242 + name: this.translate.instant('edge.unassign-from-customer'),
  243 + icon: 'assignment_return',
  244 + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && !entity.customerIsPublic),
  245 + onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
  246 + },
  247 + {
  248 + name: this.translate.instant('edge.make-private'),
  249 + icon: 'reply',
  250 + isEnabled: (entity) => (entity.customerId && entity.customerId.id !== NULL_UUID && entity.customerIsPublic),
  251 + onAction: ($event, entity) => this.unassignFromCustomer($event, entity)
  252 + },
  253 + );
  254 + }
  255 + return actions;
  256 + }
  257 +
  258 + configureGroupActions(edgeScope: string): Array<GroupActionDescriptor<EdgeInfo>> {
  259 + const actions: Array<GroupActionDescriptor<EdgeInfo>> = [];
  260 + if (edgeScope === 'tenant') {
  261 + actions.push(
  262 + {
  263 + name: this.translate.instant('edge.assign-edge-to-customer-text'),
  264 + icon: 'assignment_ind',
  265 + isEnabled: true,
  266 + onAction: ($event, entities) => this.assignToCustomer($event, entities.map((entity) => entity.id))
  267 + }
  268 + );
  269 + }
  270 + if (edgeScope === 'customer') {
  271 + actions.push(
  272 + {
  273 + name: this.translate.instant('edge.unassign-from-customer'),
  274 + icon: 'assignment_return',
  275 + isEnabled: true,
  276 + onAction: ($event, entities) => this.unassignEdgesFromCustomer($event, entities)
  277 + }
  278 + );
  279 + }
  280 + return actions;
  281 + }
  282 +
  283 + configureAddActions(edgeScope: string): Array<HeaderActionDescriptor> {
  284 + const actions: Array<HeaderActionDescriptor> = [];
  285 + if (edgeScope === 'tenant') {
  286 + actions.push(
  287 + {
  288 + name: this.translate.instant('edge.add-edge-text'),
  289 + icon: 'insert_drive_file',
  290 + isEnabled: () => true,
  291 + onAction: ($event) => this.config.table.addEntity($event)
  292 + },
  293 + {
  294 + name: this.translate.instant('edge.import'),
  295 + icon: 'file_upload',
  296 + isEnabled: () => true,
  297 + onAction: ($event) => this.importEdges($event)
  298 + }
  299 + );
  300 + }
  301 + if (edgeScope === 'customer') {
  302 + actions.push(
  303 + {
  304 + name: this.translate.instant('edge.assign-new-edge'),
  305 + icon: 'add',
  306 + isEnabled: () => true,
  307 + onAction: ($event) => this.addEdgesToCustomer($event)
  308 + }
  309 + );
  310 + }
  311 + return actions;
  312 + }
  313 +
  314 + importEdges($event: Event) {
  315 + this.homeDialogs.importEntities(EntityType.EDGE).subscribe((res) => {
  316 + if (res) {
  317 + this.broadcast.broadcast('edgeSaved');
  318 + this.config.table.updateData();
  319 + }
  320 + });
  321 + }
  322 +
  323 + addEdgesToCustomer($event: Event) {
  324 + if ($event) {
  325 + $event.stopPropagation();
  326 + }
  327 + this.dialog.open<AddEntitiesToCustomerDialogComponent, AddEntitiesToCustomerDialogData,
  328 + boolean>(AddEntitiesToCustomerDialogComponent, {
  329 + disableClose: true,
  330 + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
  331 + data: {
  332 + customerId: this.customerId,
  333 + entityType: EntityType.EDGE
  334 + }
  335 + }).afterClosed()
  336 + .subscribe((res) => {
  337 + if (res) {
  338 + this.config.table.updateData();
  339 + }
  340 + });
  341 + }
  342 +
  343 + makePublic($event: Event, edge: Edge) {
  344 + if ($event) {
  345 + $event.stopPropagation();
  346 + }
  347 + this.dialogService.confirm(
  348 + this.translate.instant('edge.make-public-edge-title', {edgeName: edge.name}),
  349 + this.translate.instant('edge.make-public-edge-text'),
  350 + this.translate.instant('action.no'),
  351 + this.translate.instant('action.yes'),
  352 + true
  353 + ).subscribe((res) => {
  354 + if (res) {
  355 + this.edgeService.makeEdgePublic(edge.id.id).subscribe(
  356 + () => {
  357 + this.config.table.updateData();
  358 + }
  359 + );
  360 + }
  361 + }
  362 + );
  363 + }
  364 +
  365 + openEdgeDashboards($event, edge) {
  366 + if ($event) {
  367 + $event.stopPropagation();
  368 + }
  369 + this.router.navigateByUrl(`edges/${edge.id.id}/dashboards`);
  370 + }
  371 +
  372 + openEdgeRuleChains($event, edge) {
  373 + if ($event) {
  374 + $event.stopPropagation();
  375 + }
  376 + this.router.navigateByUrl(`edges/${edge.id.id}/ruleChains`);
  377 + }
  378 +
  379 + openEdgeAssets($event: Event, edge: Edge) {
  380 + if ($event) {
  381 + $event.stopPropagation();
  382 + }
  383 + this.router.navigateByUrl(`edges/${edge.id.id}/assets`);
  384 + }
  385 +
  386 + openEdgeDevices($event, edge) {
  387 + if ($event) {
  388 + $event.stopPropagation();
  389 + }
  390 + this.router.navigateByUrl(`edges/${edge.id.id}/devices`);
  391 + }
  392 +
  393 + openEdgeEntityViews($event, edge) {
  394 + if ($event) {
  395 + $event.stopPropagation();
  396 + }
  397 + this.router.navigateByUrl(`edges/${edge.id.id}/entityViews`);
  398 + }
  399 +
  400 + assignToCustomer($event: Event, edgesIds: Array<EdgeId>) {
  401 + if ($event) {
  402 + $event.stopPropagation();
  403 + }
  404 + this.dialog.open<AssignToCustomerDialogComponent, AssignToCustomerDialogData,
  405 + boolean>(AssignToCustomerDialogComponent, {
  406 + disableClose: true,
  407 + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
  408 + data: {
  409 + entityIds: edgesIds,
  410 + entityType: EntityType.EDGE
  411 + }
  412 + }).afterClosed()
  413 + .subscribe((res) => {
  414 + if (res) {
  415 + this.config.table.updateData();
  416 + }
  417 + });
  418 + }
  419 +
  420 + unassignFromCustomer($event: Event, edge: EdgeInfo) {
  421 + if ($event) {
  422 + $event.stopPropagation();
  423 + }
  424 + const isPublic = edge.customerIsPublic;
  425 + let title;
  426 + let content;
  427 + if (isPublic) {
  428 + title = this.translate.instant('edge.make-private-edge-title', {edgeName: edge.name});
  429 + content = this.translate.instant('edge.make-private-edge-text');
  430 + } else {
  431 + title = this.translate.instant('edge.unassign-edge-title', {edgeName: edge.name});
  432 + content = this.translate.instant('edge.unassign-edge-text');
  433 + }
  434 + this.dialogService.confirm(
  435 + title,
  436 + content,
  437 + this.translate.instant('action.no'),
  438 + this.translate.instant('action.yes'),
  439 + true
  440 + ).subscribe((res) => {
  441 + if (res) {
  442 + this.edgeService.unassignEdgeFromCustomer(edge.id.id).subscribe(
  443 + () => {
  444 + this.config.table.updateData();
  445 + }
  446 + );
  447 + }
  448 + }
  449 + );
  450 + }
  451 +
  452 + unassignEdgesFromCustomer($event: Event, edges: Array<EdgeInfo>) {
  453 + if ($event) {
  454 + $event.stopPropagation();
  455 + }
  456 + this.dialogService.confirm(
  457 + this.translate.instant('edge.unassign-edge-title', {count: edges.length}),
  458 + this.translate.instant('edge.unassign-edge-text'),
  459 + this.translate.instant('action.no'),
  460 + this.translate.instant('action.yes'),
  461 + true
  462 + ).subscribe((res) => {
  463 + if (res) {
  464 + const tasks: Observable<any>[] = [];
  465 + edges.forEach(
  466 + (edge) => {
  467 + tasks.push(this.edgeService.unassignEdgeFromCustomer(edge.id.id));
  468 + }
  469 + );
  470 + forkJoin(tasks).subscribe(
  471 + () => {
  472 + this.config.table.updateData();
  473 + }
  474 + );
  475 + }
  476 + }
  477 + );
  478 + }
  479 +
  480 + onEdgeAction(action: EntityAction<EdgeInfo>): boolean {
  481 + switch (action.action) {
  482 + case 'makePublic':
  483 + this.makePublic(action.event, action.entity);
  484 + return true;
  485 + case 'assignToCustomer':
  486 + this.assignToCustomer(action.event, [action.entity.id]);
  487 + return true;
  488 + case 'unassignFromCustomer':
  489 + this.unassignFromCustomer(action.event, action.entity);
  490 + return true;
  491 + case 'openEdgeAssets':
  492 + this.openEdgeAssets(action.event, action.entity);
  493 + return true;
  494 + case 'openEdgeDevices':
  495 + this.openEdgeDevices(action.event, action.entity);
  496 + return true;
  497 + case 'openEdgeEntityViews':
  498 + this.openEdgeEntityViews(action.event, action.entity);
  499 + return true;
  500 + case 'openEdgeDashboards':
  501 + this.openEdgeDashboards(action.event, action.entity);
  502 + return true;
  503 + case 'openEdgeRuleChains':
  504 + this.openEdgeRuleChains(action.event, action.entity);
  505 + return true;
  506 + }
  507 + }
  508 +
  509 +}
@@ -109,7 +109,8 @@ export class RuleNodeComponentsResolver implements Resolve<Array<RuleNodeCompone @@ -109,7 +109,8 @@ export class RuleNodeComponentsResolver implements Resolve<Array<RuleNodeCompone
109 } 109 }
110 110
111 resolve(route: ActivatedRouteSnapshot): Observable<Array<RuleNodeComponentDescriptor>> { 111 resolve(route: ActivatedRouteSnapshot): Observable<Array<RuleNodeComponentDescriptor>> {
112 - return this.ruleChainService.getRuleNodeComponents(ruleNodeConfigResourcesModulesMap); 112 + const type = route.data.type;
  113 + return this.ruleChainService.getRuleNodeComponents(ruleNodeConfigResourcesModulesMap, type);
113 } 114 }
114 } 115 }
115 116
@@ -27,7 +27,7 @@ import { TranslateService } from '@ngx-translate/core'; @@ -27,7 +27,7 @@ import { TranslateService } from '@ngx-translate/core';
27 import { DatePipe } from '@angular/common'; 27 import { DatePipe } from '@angular/common';
28 import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; 28 import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
29 import { EntityAction } from '@home/models/entity/entity-component.models'; 29 import { EntityAction } from '@home/models/entity/entity-component.models';
30 -import { RuleChain } from '@shared/models/rule-chain.models'; 30 +import {RuleChain, ruleChainType} from '@shared/models/rule-chain.models';
31 import { RuleChainService } from '@core/http/rule-chain.service'; 31 import { RuleChainService } from '@core/http/rule-chain.service';
32 import { RuleChainComponent } from '@modules/home/pages/rulechain/rulechain.component'; 32 import { RuleChainComponent } from '@modules/home/pages/rulechain/rulechain.component';
33 import { DialogService } from '@core/services/dialog.service'; 33 import { DialogService } from '@core/services/dialog.service';
@@ -105,7 +105,7 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig< @@ -105,7 +105,7 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
105 this.config.deleteEntitiesTitle = count => this.translate.instant('rulechain.delete-rulechains-title', {count}); 105 this.config.deleteEntitiesTitle = count => this.translate.instant('rulechain.delete-rulechains-title', {count});
106 this.config.deleteEntitiesContent = () => this.translate.instant('rulechain.delete-rulechains-text'); 106 this.config.deleteEntitiesContent = () => this.translate.instant('rulechain.delete-rulechains-text');
107 107
108 - this.config.entitiesFetchFunction = pageLink => this.ruleChainService.getRuleChains(pageLink); 108 + this.config.entitiesFetchFunction = pageLink => this.ruleChainService.getRuleChains(pageLink, ruleChainType.core);
109 this.config.loadEntity = id => this.ruleChainService.getRuleChain(id.id); 109 this.config.loadEntity = id => this.ruleChainService.getRuleChain(id.id);
110 this.config.saveEntity = ruleChain => this.ruleChainService.saveRuleChain(ruleChain); 110 this.config.saveEntity = ruleChain => this.ruleChainService.saveRuleChain(ruleChain);
111 this.config.deleteEntity = id => this.ruleChainService.deleteRuleChain(id.id); 111 this.config.deleteEntity = id => this.ruleChainService.deleteRuleChain(id.id);
@@ -153,6 +153,11 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit @@ -153,6 +153,11 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
153 this.noEntitiesMatchingText = 'device.no-devices-matching'; 153 this.noEntitiesMatchingText = 'device.no-devices-matching';
154 this.entityRequiredText = 'device.device-required'; 154 this.entityRequiredText = 'device.device-required';
155 break; 155 break;
  156 + case EntityType.EDGE:
  157 + this.entityText = 'edge.edge';
  158 + this.noEntitiesMatchingText = 'edge.no-edges-matching';
  159 + this.entityRequiredText = 'edge.edge-required';
  160 + break;
156 case EntityType.ENTITY_VIEW: 161 case EntityType.ENTITY_VIEW:
157 this.entityText = 'entity-view.entity-view'; 162 this.entityText = 'entity-view.entity-view';
158 this.noEntitiesMatchingText = 'entity-view.no-entity-views-matching'; 163 this.noEntitiesMatchingText = 'entity-view.no-entity-views-matching';
@@ -27,6 +27,7 @@ import { BroadcastService } from '@app/core/services/broadcast.service'; @@ -27,6 +27,7 @@ import { BroadcastService } from '@app/core/services/broadcast.service';
27 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 27 import { coerceBooleanProperty } from '@angular/cdk/coercion';
28 import { AssetService } from '@core/http/asset.service'; 28 import { AssetService } from '@core/http/asset.service';
29 import { EntityViewService } from '@core/http/entity-view.service'; 29 import { EntityViewService } from '@core/http/entity-view.service';
  30 +import { EdgeService } from "@core/http/edge.service";
30 31
31 @Component({ 32 @Component({
32 selector: 'tb-entity-subtype-autocomplete', 33 selector: 'tb-entity-subtype-autocomplete',
@@ -82,6 +83,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -82,6 +83,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
82 public translate: TranslateService, 83 public translate: TranslateService,
83 private deviceService: DeviceService, 84 private deviceService: DeviceService,
84 private assetService: AssetService, 85 private assetService: AssetService,
  86 + private edgeService: EdgeService,
85 private entityViewService: EntityViewService, 87 private entityViewService: EntityViewService,
86 private fb: FormBuilder) { 88 private fb: FormBuilder) {
87 this.subTypeFormGroup = this.fb.group({ 89 this.subTypeFormGroup = this.fb.group({
@@ -115,6 +117,14 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -115,6 +117,14 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
115 this.subTypes = null; 117 this.subTypes = null;
116 }); 118 });
117 break; 119 break;
  120 + case EntityType.EDGE:
  121 + this.selectEntitySubtypeText = 'edge.select-edge-type';
  122 + this.entitySubtypeText = 'edge.edge-type';
  123 + this.entitySubtypeRequiredText = 'edge.edge-type-required';
  124 + this.broadcastSubscription = this.broadcast.on('edgeSaved', () => {
  125 + this.subTypes = null;
  126 + });
  127 + break;
118 case EntityType.ENTITY_VIEW: 128 case EntityType.ENTITY_VIEW:
119 this.selectEntitySubtypeText = 'entity-view.select-entity-view-type'; 129 this.selectEntitySubtypeText = 'entity-view.select-entity-view-type';
120 this.entitySubtypeText = 'entity-view.entity-view-type'; 130 this.entitySubtypeText = 'entity-view.entity-view-type';
@@ -202,6 +212,9 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor, @@ -202,6 +212,9 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
202 case EntityType.DEVICE: 212 case EntityType.DEVICE:
203 subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true}); 213 subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true});
204 break; 214 break;
  215 + case EntityType.EDGE:
  216 + subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true});
  217 + break;
205 case EntityType.ENTITY_VIEW: 218 case EntityType.ENTITY_VIEW:
206 subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true}); 219 subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
207 break; 220 break;
@@ -27,6 +27,7 @@ import { MatChipInputEvent, MatChipList } from '@angular/material/chips'; @@ -27,6 +27,7 @@ import { MatChipInputEvent, MatChipList } from '@angular/material/chips';
27 import { coerceBooleanProperty } from '@angular/cdk/coercion'; 27 import { coerceBooleanProperty } from '@angular/cdk/coercion';
28 import { AssetService } from '@core/http/asset.service'; 28 import { AssetService } from '@core/http/asset.service';
29 import { DeviceService } from '@core/http/device.service'; 29 import { DeviceService } from '@core/http/device.service';
  30 +import { EdgeService } from "@core/http/edge.service";
30 import { EntityViewService } from '@core/http/entity-view.service'; 31 import { EntityViewService } from '@core/http/entity-view.service';
31 import { BroadcastService } from '@core/services/broadcast.service'; 32 import { BroadcastService } from '@core/services/broadcast.service';
32 import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; 33 import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
@@ -96,6 +97,7 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, @@ -96,6 +97,7 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
96 public translate: TranslateService, 97 public translate: TranslateService,
97 private assetService: AssetService, 98 private assetService: AssetService,
98 private deviceService: DeviceService, 99 private deviceService: DeviceService,
  100 + private edgeService: EdgeService,
99 private entityViewService: EntityViewService, 101 private entityViewService: EntityViewService,
100 private fb: FormBuilder) { 102 private fb: FormBuilder) {
101 this.entitySubtypeListFormGroup = this.fb.group({ 103 this.entitySubtypeListFormGroup = this.fb.group({
@@ -139,6 +141,15 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, @@ -139,6 +141,15 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
139 this.entitySubtypes = null; 141 this.entitySubtypes = null;
140 }); 142 });
141 break; 143 break;
  144 + case EntityType.EDGE:
  145 + this.placeholder = this.required ? this.translate.instant('edge.enter-edge-type')
  146 + : this.translate.instant('edge-any-edge');
  147 + this.secondaryPlaceholder = '+' + this.translate.instant('edge.edge-type');
  148 + this.noSubtypesMathingText = 'edge.no-edge-types-matching';
  149 + this.broadcastSubscription = this.broadcast.on('edgeSaved', () => {
  150 + this.entitySubtypes = null;
  151 + });
  152 + break;
142 case EntityType.ENTITY_VIEW: 153 case EntityType.ENTITY_VIEW:
143 this.placeholder = this.required ? this.translate.instant('entity-view.enter-entity-view-type') 154 this.placeholder = this.required ? this.translate.instant('entity-view.enter-entity-view-type')
144 : this.translate.instant('entity-view.any-entity-view'); 155 : this.translate.instant('entity-view.any-entity-view');
@@ -260,6 +271,9 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, @@ -260,6 +271,9 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
260 case EntityType.DEVICE: 271 case EntityType.DEVICE:
261 subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true}); 272 subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true});
262 break; 273 break;
  274 + case EntityType.EDGE:
  275 + subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true});
  276 + break;
263 case EntityType.ENTITY_VIEW: 277 case EntityType.ENTITY_VIEW:
264 subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true}); 278 subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
265 break; 279 break;
@@ -25,6 +25,7 @@ import { DeviceService } from '@core/http/device.service'; @@ -25,6 +25,7 @@ import { DeviceService } from '@core/http/device.service';
25 import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models'; 25 import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models';
26 import { BroadcastService } from '@app/core/services/broadcast.service'; 26 import { BroadcastService } from '@app/core/services/broadcast.service';
27 import { AssetService } from '@core/http/asset.service'; 27 import { AssetService } from '@core/http/asset.service';
  28 +import { EdgeService } from "@core/http/edge.service";
28 import { EntityViewService } from '@core/http/entity-view.service'; 29 import { EntityViewService } from '@core/http/entity-view.service';
29 30
30 @Component({ 31 @Component({
@@ -78,6 +79,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni @@ -78,6 +79,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
78 public translate: TranslateService, 79 public translate: TranslateService,
79 private deviceService: DeviceService, 80 private deviceService: DeviceService,
80 private assetService: AssetService, 81 private assetService: AssetService,
  82 + private edgeService: EdgeService,
81 private entityViewService: EntityViewService, 83 private entityViewService: EntityViewService,
82 private fb: FormBuilder) { 84 private fb: FormBuilder) {
83 this.subTypeFormGroup = this.fb.group({ 85 this.subTypeFormGroup = this.fb.group({
@@ -111,6 +113,14 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni @@ -111,6 +113,14 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
111 this.subTypesOptionsSubject.next(''); 113 this.subTypesOptionsSubject.next('');
112 }); 114 });
113 break; 115 break;
  116 + case EntityType.EDGE:
  117 + this.entitySubtypeTitle = 'edge.edge-type';
  118 + this.entitySubtypeRequiredText = 'edge.edge-type-required';
  119 + this.broadcastSubscription = this.broadcast.on('edgeSaved',() => {
  120 + this.subTypes = null;
  121 + this.subTypesOptionsSubject.next('');
  122 + });
  123 + break;
114 case EntityType.ENTITY_VIEW: 124 case EntityType.ENTITY_VIEW:
115 this.entitySubtypeTitle = 'entity-view.entity-view-type'; 125 this.entitySubtypeTitle = 'entity-view.entity-view-type';
116 this.entitySubtypeRequiredText = 'entity-view.entity-view-type-required'; 126 this.entitySubtypeRequiredText = 'entity-view.entity-view-type-required';
@@ -208,6 +218,9 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni @@ -208,6 +218,9 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
208 case EntityType.DEVICE: 218 case EntityType.DEVICE:
209 this.subTypes = this.deviceService.getDeviceTypes({ignoreLoading: true}); 219 this.subTypes = this.deviceService.getDeviceTypes({ignoreLoading: true});
210 break; 220 break;
  221 + case EntityType.EDGE:
  222 + this.subTypes = this.edgeService.getEdgeTypes({ignoreLoading: true});
  223 + break;
211 case EntityType.ENTITY_VIEW: 224 case EntityType.ENTITY_VIEW:
212 this.subTypes = this.entityViewService.getEntityViewTypes({ignoreLoading: true}); 225 this.subTypes = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
213 break; 226 break;
@@ -26,10 +26,12 @@ export enum AliasFilterType { @@ -26,10 +26,12 @@ export enum AliasFilterType {
26 stateEntity = 'stateEntity', 26 stateEntity = 'stateEntity',
27 assetType = 'assetType', 27 assetType = 'assetType',
28 deviceType = 'deviceType', 28 deviceType = 'deviceType',
  29 + edgeType = 'edgeType',
29 entityViewType = 'entityViewType', 30 entityViewType = 'entityViewType',
30 relationsQuery = 'relationsQuery', 31 relationsQuery = 'relationsQuery',
31 assetSearchQuery = 'assetSearchQuery', 32 assetSearchQuery = 'assetSearchQuery',
32 deviceSearchQuery = 'deviceSearchQuery', 33 deviceSearchQuery = 'deviceSearchQuery',
  34 + edgeSearchQuery = 'edgeSearchQuery',
33 entityViewSearchQuery = 'entityViewSearchQuery' 35 entityViewSearchQuery = 'entityViewSearchQuery'
34 } 36 }
35 37
@@ -41,10 +43,12 @@ export const aliasFilterTypeTranslationMap = new Map<AliasFilterType, string>( @@ -41,10 +43,12 @@ export const aliasFilterTypeTranslationMap = new Map<AliasFilterType, string>(
41 [ AliasFilterType.stateEntity, 'alias.filter-type-state-entity' ], 43 [ AliasFilterType.stateEntity, 'alias.filter-type-state-entity' ],
42 [ AliasFilterType.assetType, 'alias.filter-type-asset-type' ], 44 [ AliasFilterType.assetType, 'alias.filter-type-asset-type' ],
43 [ AliasFilterType.deviceType, 'alias.filter-type-device-type' ], 45 [ AliasFilterType.deviceType, 'alias.filter-type-device-type' ],
  46 + [ AliasFilterType.edgeType, 'alias.filter-type-edge-type' ],
44 [ AliasFilterType.entityViewType, 'alias.filter-type-entity-view-type' ], 47 [ AliasFilterType.entityViewType, 'alias.filter-type-entity-view-type' ],
45 [ AliasFilterType.relationsQuery, 'alias.filter-type-relations-query' ], 48 [ AliasFilterType.relationsQuery, 'alias.filter-type-relations-query' ],
46 [ AliasFilterType.assetSearchQuery, 'alias.filter-type-asset-search-query' ], 49 [ AliasFilterType.assetSearchQuery, 'alias.filter-type-asset-search-query' ],
47 [ AliasFilterType.deviceSearchQuery, 'alias.filter-type-device-search-query' ], 50 [ AliasFilterType.deviceSearchQuery, 'alias.filter-type-device-search-query' ],
  51 + [ AliasFilterType.edgeSearchQuery, 'alias.filter-type-edge-search-query' ],
48 [ AliasFilterType.entityViewSearchQuery, 'alias.filter-type-entity-view-search-query' ] 52 [ AliasFilterType.entityViewSearchQuery, 'alias.filter-type-entity-view-search-query' ]
49 ] 53 ]
50 ); 54 );
@@ -78,6 +82,11 @@ export interface DeviceTypeFilter { @@ -78,6 +82,11 @@ export interface DeviceTypeFilter {
78 deviceNameFilter?: string; 82 deviceNameFilter?: string;
79 } 83 }
80 84
  85 +export interface EdgeTypeFilter {
  86 + edgeType?: string;
  87 + edgeNameFilter?: string;
  88 +}
  89 +
81 export interface EntityViewFilter { 90 export interface EntityViewFilter {
82 entityViewType?: string; 91 entityViewType?: string;
83 entityViewNameFilter?: string; 92 entityViewNameFilter?: string;
@@ -113,6 +122,10 @@ export interface DeviceSearchQueryFilter extends EntitySearchQueryFilter { @@ -113,6 +122,10 @@ export interface DeviceSearchQueryFilter extends EntitySearchQueryFilter {
113 deviceTypes?: string[]; 122 deviceTypes?: string[];
114 } 123 }
115 124
  125 +export interface EdgeSearchQueryFilter extends EntitySearchQueryFilter {
  126 + edgeTypes?: string[];
  127 +}
  128 +
116 export interface EntityViewSearchQueryFilter extends EntitySearchQueryFilter { 129 export interface EntityViewSearchQueryFilter extends EntitySearchQueryFilter {
117 entityViewTypes?: string[]; 130 entityViewTypes?: string[];
118 } 131 }
@@ -124,10 +137,12 @@ export type EntityFilters = @@ -124,10 +137,12 @@ export type EntityFilters =
124 StateEntityFilter & 137 StateEntityFilter &
125 AssetTypeFilter & 138 AssetTypeFilter &
126 DeviceTypeFilter & 139 DeviceTypeFilter &
  140 + EdgeTypeFilter &
127 EntityViewFilter & 141 EntityViewFilter &
128 RelationsQueryFilter & 142 RelationsQueryFilter &
129 AssetSearchQueryFilter & 143 AssetSearchQueryFilter &
130 DeviceSearchQueryFilter & 144 DeviceSearchQueryFilter &
  145 + EdgeSearchQueryFilter &
131 EntityViewSearchQueryFilter; 146 EntityViewSearchQueryFilter;
132 147
133 export interface EntityAliasFilter extends EntityFilters { 148 export interface EntityAliasFilter extends EntityFilters {
@@ -19,10 +19,12 @@ import { AssetId } from './id/asset-id'; @@ -19,10 +19,12 @@ import { AssetId } from './id/asset-id';
19 import { TenantId } from '@shared/models/id/tenant-id'; 19 import { TenantId } from '@shared/models/id/tenant-id';
20 import { CustomerId } from '@shared/models/id/customer-id'; 20 import { CustomerId } from '@shared/models/id/customer-id';
21 import { EntitySearchQuery } from '@shared/models/relation.models'; 21 import { EntitySearchQuery } from '@shared/models/relation.models';
  22 +import { EdgeId } from "@shared/models/id/edge-id";
22 23
23 export interface Asset extends BaseData<AssetId> { 24 export interface Asset extends BaseData<AssetId> {
24 tenantId?: TenantId; 25 tenantId?: TenantId;
25 customerId?: CustomerId; 26 customerId?: CustomerId;
  27 + edgeId?: EdgeId; //TODO: deaflynx: "edgeId?" ?
26 name: string; 28 name: string;
27 type: string; 29 type: string;
28 label: string; 30 label: string;
@@ -49,7 +49,9 @@ export enum ActionType { @@ -49,7 +49,9 @@ export enum ActionType {
49 ALARM_CLEAR = 'ALARM_CLEAR', 49 ALARM_CLEAR = 'ALARM_CLEAR',
50 LOGIN = 'LOGIN', 50 LOGIN = 'LOGIN',
51 LOGOUT = 'LOGOUT', 51 LOGOUT = 'LOGOUT',
52 - LOCKOUT = 'LOCKOUT' 52 + LOCKOUT = 'LOCKOUT',
  53 + ASSIGNED_TO_EDGE = 'ASSIGNED_TO_EDGE',
  54 + UNASSIGNED_FROM_EDGE = 'UNASSIGNED_FROM_EDGE'
53 } 55 }
54 56
55 export enum ActionStatus { 57 export enum ActionStatus {
@@ -79,7 +81,9 @@ export const actionTypeTranslations = new Map<ActionType, string>( @@ -79,7 +81,9 @@ export const actionTypeTranslations = new Map<ActionType, string>(
79 [ActionType.ALARM_CLEAR, 'audit-log.type-alarm-clear'], 81 [ActionType.ALARM_CLEAR, 'audit-log.type-alarm-clear'],
80 [ActionType.LOGIN, 'audit-log.type-login'], 82 [ActionType.LOGIN, 'audit-log.type-login'],
81 [ActionType.LOGOUT, 'audit-log.type-logout'], 83 [ActionType.LOGOUT, 'audit-log.type-logout'],
82 - [ActionType.LOCKOUT, 'audit-log.type-lockout'] 84 + [ActionType.LOCKOUT, 'audit-log.type-lockout'],
  85 + [ActionType.ASSIGNED_TO_EDGE, 'audit-log.type-assigned-to-edge'],
  86 + [ActionType.UNASSIGNED_FROM_EDGE, 'audit-log.type-unassigned-from-edge']
83 ] 87 ]
84 ); 88 );
85 89
@@ -97,6 +97,7 @@ export const HelpLinks = { @@ -97,6 +97,7 @@ export const HelpLinks = {
97 customers: helpBaseUrl + '/docs/user-guide/customers', 97 customers: helpBaseUrl + '/docs/user-guide/customers',
98 users: helpBaseUrl + '/docs/user-guide/ui/users', 98 users: helpBaseUrl + '/docs/user-guide/ui/users',
99 devices: helpBaseUrl + '/docs/user-guide/ui/devices', 99 devices: helpBaseUrl + '/docs/user-guide/ui/devices',
  100 + edges: helpBaseUrl + 'docs/user-guide/ui/edges',
100 assets: helpBaseUrl + '/docs/user-guide/ui/assets', 101 assets: helpBaseUrl + '/docs/user-guide/ui/assets',
101 entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views', 102 entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views',
102 entitiesImport: helpBaseUrl + '/docs/user-guide/bulk-provisioning', 103 entitiesImport: helpBaseUrl + '/docs/user-guide/bulk-provisioning',
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { BaseData } from '@shared/models/base-data';
  18 +import { TenantId } from '@shared/models/id/tenant-id';
  19 +import { CustomerId } from '@shared/models/id/customer-id';
  20 +import { EdgeId } from '@shared/models/id/edge-id';
  21 +import { EntitySearchQuery } from '@shared/models/relation.models';
  22 +
  23 +export interface Edge extends BaseData<EdgeId> {
  24 + tenantId?: TenantId;
  25 + customerId?: CustomerId;
  26 + name: string;
  27 + type: string;
  28 + secret: string;
  29 + routingKey: string;
  30 + label?: string;
  31 + additionalInfo?: any;
  32 +}
  33 +
  34 +export interface EdgeInfo extends Edge {
  35 + customerTitle: string;
  36 + customerIsPublic: boolean;
  37 + // assignedCustomers?: Array<ShortCustomerInfo> //TODO: deaflynx check usage
  38 +}
  39 +
  40 +export interface EdgeSearchQuery extends EntitySearchQuery {
  41 + edgeTypes: Array<string>;
  42 +}
@@ -43,6 +43,7 @@ export enum EntityType { @@ -43,6 +43,7 @@ export enum EntityType {
43 ALARM = 'ALARM', 43 ALARM = 'ALARM',
44 RULE_CHAIN = 'RULE_CHAIN', 44 RULE_CHAIN = 'RULE_CHAIN',
45 RULE_NODE = 'RULE_NODE', 45 RULE_NODE = 'RULE_NODE',
  46 + EDGE = 'EDGE',
46 ENTITY_VIEW = 'ENTITY_VIEW', 47 ENTITY_VIEW = 'ENTITY_VIEW',
47 WIDGETS_BUNDLE = 'WIDGETS_BUNDLE', 48 WIDGETS_BUNDLE = 'WIDGETS_BUNDLE',
48 WIDGET_TYPE = 'WIDGET_TYPE' 49 WIDGET_TYPE = 'WIDGET_TYPE'
@@ -143,6 +144,20 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti @@ -143,6 +144,20 @@ export const entityTypeTranslations = new Map<EntityType | AliasEntityType, Enti
143 } 144 }
144 ], 145 ],
145 [ 146 [
  147 + EntityType.EDGE,
  148 + {
  149 + type: 'entity.type-edge',
  150 + typePlural: 'entity.type-edges',
  151 + list: 'entity.list-of-edges',
  152 + nameStartsWith: 'entity.edge-name-starts-with',
  153 + details: 'edge.edge-details',
  154 + add: 'edge.add',
  155 + noEntities: 'edge.no-edges-text',
  156 + search: 'edge.search',
  157 + selectedEntities: 'edge.selected-edges'
  158 + }
  159 + ],
  160 + [
146 EntityType.ENTITY_VIEW, 161 EntityType.ENTITY_VIEW,
147 { 162 {
148 type: 'entity.type-entity-view', 163 type: 'entity.type-entity-view',
@@ -266,6 +281,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa @@ -266,6 +281,12 @@ export const entityTypeResources = new Map<EntityType, EntityTypeResource<BaseDa
266 } 281 }
267 ], 282 ],
268 [ 283 [
  284 + EntityType.EDGE,
  285 + {
  286 + helpLinkId: 'edges'
  287 + }
  288 + ],
  289 + [
269 EntityType.ENTITY_VIEW, 290 EntityType.ENTITY_VIEW,
270 { 291 {
271 helpLinkId: 'entityViews' 292 helpLinkId: 'entityViews'
  1 +///
  2 +/// Copyright © 2016-2020 The Thingsboard Authors
  3 +///
  4 +/// Licensed under the Apache License, Version 2.0 (the "License");
  5 +/// you may not use this file except in compliance with the License.
  6 +/// You may obtain a copy of the License at
  7 +///
  8 +/// http://www.apache.org/licenses/LICENSE-2.0
  9 +///
  10 +/// Unless required by applicable law or agreed to in writing, software
  11 +/// distributed under the License is distributed on an "AS IS" BASIS,
  12 +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +/// See the License for the specific language governing permissions and
  14 +/// limitations under the License.
  15 +///
  16 +
  17 +import { EntityId } from './entity-id';
  18 +import { EntityType } from '@shared/models/entity-type.models';
  19 +
  20 +export class EdgeId implements EntityId {
  21 + entityType = EntityType.EDGE;
  22 + id: string;
  23 + constructor(id: string) {
  24 + this.id = id;
  25 + }
  26 +}
@@ -29,6 +29,7 @@ export * from './contact-based.model'; @@ -29,6 +29,7 @@ export * from './contact-based.model';
29 export * from './customer.model'; 29 export * from './customer.model';
30 export * from './dashboard.models'; 30 export * from './dashboard.models';
31 export * from './device.models'; 31 export * from './device.models';
  32 +export * from './edge.models';
32 export * from './entity.models'; 33 export * from './entity.models';
33 export * from './entity-type.models'; 34 export * from './entity-type.models';
34 export * from './entity-view.models'; 35 export * from './entity-view.models';
@@ -27,6 +27,7 @@ export interface RuleChain extends BaseData<RuleChainId> { @@ -27,6 +27,7 @@ export interface RuleChain extends BaseData<RuleChainId> {
27 firstRuleNodeId: RuleNodeId; 27 firstRuleNodeId: RuleNodeId;
28 root: boolean; 28 root: boolean;
29 debugMode: boolean; 29 debugMode: boolean;
  30 + type: string;
30 configuration?: any; 31 configuration?: any;
31 additionalInfo?: any; 32 additionalInfo?: any;
32 } 33 }
@@ -62,6 +63,11 @@ export interface RuleChainConnectionInfo { @@ -62,6 +63,11 @@ export interface RuleChainConnectionInfo {
62 type: string; 63 type: string;
63 } 64 }
64 65
  66 +export interface RuleChainType {
  67 + core: string;
  68 + edge: string;
  69 +}
  70 +
65 export const ruleNodeTypeComponentTypes: ComponentType[] = 71 export const ruleNodeTypeComponentTypes: ComponentType[] =
66 [ 72 [
67 ComponentType.FILTER, 73 ComponentType.FILTER,
@@ -110,3 +116,8 @@ export const inputNodeComponent: RuleNodeComponentDescriptor = { @@ -110,3 +116,8 @@ export const inputNodeComponent: RuleNodeComponentDescriptor = {
110 name: 'Input', 116 name: 'Input',
111 clazz: 'tb.internal.Input' 117 clazz: 'tb.internal.Input'
112 }; 118 };
  119 +
  120 +export const ruleChainType: RuleChainType = {
  121 + core: 'CORE',
  122 + edge: 'EDGE'
  123 +}
@@ -67,7 +67,7 @@ @@ -67,7 +67,7 @@
67 "general-settings": "Allgemeine Einstellungen", 67 "general-settings": "Allgemeine Einstellungen",
68 "outgoing-mail": "E-Mail Versand", 68 "outgoing-mail": "E-Mail Versand",
69 "outgoing-mail-settings": "Konfiguration des Postausgangsservers", 69 "outgoing-mail-settings": "Konfiguration des Postausgangsservers",
70 - "system-settings": "Systeminstellungen", 70 + "system-settings": "Systemeinstellungen",
71 "test-mail-sent": "Test E-Mail wurde erfolgreich versendet!", 71 "test-mail-sent": "Test E-Mail wurde erfolgreich versendet!",
72 "base-url": "Basis-URL", 72 "base-url": "Basis-URL",
73 "base-url-required": "Basis-URL ist erforderlich.", 73 "base-url-required": "Basis-URL ist erforderlich.",
@@ -183,8 +183,6 @@ @@ -183,8 +183,6 @@
183 "filter-type-entity-view-type": "Entitätsansichtstyp", 183 "filter-type-entity-view-type": "Entitätsansichtstyp",
184 "filter-type-entity-view-type-description": "Entitätsansichten vom Typ '{{entityView}}'", 184 "filter-type-entity-view-type-description": "Entitätsansichten vom Typ '{{entityView}}'",
185 "filter-type-entity-view-type-and-name-description": "Entitätsansichten vom Typ '{{entityView}}' und Name beginnend mit '{{prefix}}'", 185 "filter-type-entity-view-type-and-name-description": "Entitätsansichten vom Typ '{{entityView}}' und Name beginnend mit '{{prefix}}'",
186 - "filter-type-edge-type": "Randtyp",  
187 - "filter-type-edge-type-description": "Rand vom Typ '{{edgeType}}'",  
188 "filter-type-relations-query": "Beziehungsabfrage", 186 "filter-type-relations-query": "Beziehungsabfrage",
189 "filter-type-relations-query-description": "{{entities}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", 187 "filter-type-relations-query-description": "{{entities}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}",
190 "filter-type-asset-search-query": "Objektabfrage", 188 "filter-type-asset-search-query": "Objektabfrage",
@@ -193,8 +191,6 @@ @@ -193,8 +191,6 @@
193 "filter-type-device-search-query-description": "Geräte vom Typ {{deviceTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", 191 "filter-type-device-search-query-description": "Geräte vom Typ {{deviceTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}",
194 "filter-type-entity-view-search-query": "Entitätsansichtsabfrage", 192 "filter-type-entity-view-search-query": "Entitätsansichtsabfrage",
195 "filter-type-entity-view-search-query-description": "Entitätsansichten vom Typ {{entityViewTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}", 193 "filter-type-entity-view-search-query-description": "Entitätsansichten vom Typ {{entityViewTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}",
196 - "filter-type-edge-search-query": "Randabfrage",  
197 - "filter-type-edge-search-query-description": "Rand vom Typ {{edgeTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}",  
198 "entity-filter": "Entitätsfilter", 194 "entity-filter": "Entitätsfilter",
199 "resolve-multiple": "Als mehrere Entitäten auflösen", 195 "resolve-multiple": "Als mehrere Entitäten auflösen",
200 "filter-type": "Filtertyp", 196 "filter-type": "Filtertyp",
@@ -273,14 +269,7 @@ @@ -273,14 +269,7 @@
273 "no-assets-matching": "Es wurden keine zu '{{entity}}' passenden Objekte gefunden.", 269 "no-assets-matching": "Es wurden keine zu '{{entity}}' passenden Objekte gefunden.",
274 "asset-required": "Objekt ist erforderlich", 270 "asset-required": "Objekt ist erforderlich",
275 "name-starts-with": "Name des Objekts beginnt mit", 271 "name-starts-with": "Name des Objekts beginnt mit",
276 - "label": "Bezeichnung",  
277 - "assign-asset-to-edge": "Objekte dem Rand zuordnen",  
278 - "assign-asset-to-edge-text":"Bitte wählen Sie die Objekte aus, die dem Rand zugeordnet werden sollen",  
279 - "unassign-from-edge": "Randzuordnung aufheben",  
280 - "assign-to-edge": "Einem Rand zuordnen",  
281 - "unassign-asset-from-edge-title": "Sind Sie sicher, dass Sie die Zuordnung für das Objekt '{{assetName}}' aufheben möchten?",  
282 - "unassign-asset-from-edge-text": "Nach Bestätigung wird die Zuordnung des Objekts aufgehoben und es ist für den Kunden nicht mehr zugänglich.",  
283 - "unassign-assets-from-edge-action-title": "Rand { count, plural, 1 {1 Objektzuordnung} other {# Objektzuordnungen} } aufheben" 272 + "label": "Bezeichnung"
284 }, 273 },
285 "attribute": { 274 "attribute": {
286 "attributes": "Eigenschaften", 275 "attributes": "Eigenschaften",
@@ -328,8 +317,6 @@ @@ -328,8 +317,6 @@
328 "type-credentials-updated": "Anmeldeinformationen wurden aktualisiert", 317 "type-credentials-updated": "Anmeldeinformationen wurden aktualisiert",
329 "type-assigned-to-customer": "Kunden Zuordnung", 318 "type-assigned-to-customer": "Kunden Zuordnung",
330 "type-unassigned-from-customer": "Kunden Zuordnung aufgehoben", 319 "type-unassigned-from-customer": "Kunden Zuordnung aufgehoben",
331 - "type-assigned-to-edge": "Rand Zuordnung",  
332 - "type-unassigned-from-edge": "Rand Zuordnung aufgehoben",  
333 "type-activated": "Aktiviert", 320 "type-activated": "Aktiviert",
334 "type-suspended": "Ausgesetzt", 321 "type-suspended": "Ausgesetzt",
335 "type-credentials-read": "Anmeldeinformationen gelesen", 322 "type-credentials-read": "Anmeldeinformationen gelesen",
@@ -394,7 +381,6 @@ @@ -394,7 +381,6 @@
394 "public-devices": "Öffentliche Geräte", 381 "public-devices": "Öffentliche Geräte",
395 "public-assets": "Öffentliche Objekte", 382 "public-assets": "Öffentliche Objekte",
396 "public-entity-views": "Öffentliche Entitätsansichten", 383 "public-entity-views": "Öffentliche Entitätsansichten",
397 - "public-edges": "Öffentliche Rand",  
398 "add": "Kunde hinzufügen", 384 "add": "Kunde hinzufügen",
399 "delete": "Kunde löschen", 385 "delete": "Kunde löschen",
400 "manage-customer-users": "Kundenbenutzer verwalten", 386 "manage-customer-users": "Kundenbenutzer verwalten",
@@ -403,9 +389,7 @@ @@ -403,9 +389,7 @@
403 "manage-public-devices": "Öffentliche Geräte verwalten", 389 "manage-public-devices": "Öffentliche Geräte verwalten",
404 "manage-public-dashboards": "Öffentliche Dashboards verwalten", 390 "manage-public-dashboards": "Öffentliche Dashboards verwalten",
405 "manage-customer-assets": "Kundenobjekte verwalten", 391 "manage-customer-assets": "Kundenobjekte verwalten",
406 - "manage-customer-edges": "Randobjekte verwalten",  
407 "manage-public-assets": "Öffentliche Objekte verwalten", 392 "manage-public-assets": "Öffentliche Objekte verwalten",
408 - "manage-public-edges": "Öffentliche Rand verwalten",  
409 "add-customer-text": "Neuen Kunden hinzufügen", 393 "add-customer-text": "Neuen Kunden hinzufügen",
410 "no-customers-text": "Keine Kunden gefunden", 394 "no-customers-text": "Keine Kunden gefunden",
411 "customer-details": "Kundendetails", 395 "customer-details": "Kundendetails",
@@ -430,7 +414,6 @@ @@ -430,7 +414,6 @@
430 "customer-required": "Kunde ist erforderlich", 414 "customer-required": "Kunde ist erforderlich",
431 "select-default-customer": "Wählen Sie den Standardkunden aus.", 415 "select-default-customer": "Wählen Sie den Standardkunden aus.",
432 "default-customer": "Standardkunde", 416 "default-customer": "Standardkunde",
433 - "edges": "Kunden Rand",  
434 "default-customer-required": "Ein Standardkunde ist erforderlich, um das Dashboard auf Mandantenebene zu testen." 417 "default-customer-required": "Ein Standardkunde ist erforderlich, um das Dashboard auf Mandantenebene zu testen."
435 }, 418 },
436 "datetime": { 419 "datetime": {
@@ -578,21 +561,7 @@ @@ -578,21 +561,7 @@
578 "show-details": "Details anzeigen", 561 "show-details": "Details anzeigen",
579 "hide-details": "Details ausblenden", 562 "hide-details": "Details ausblenden",
580 "select-state": "Soll-Zustand auswählen", 563 "select-state": "Soll-Zustand auswählen",
581 - "state-controller": "Zustandssteuerung",  
582 - "manage-assigned-edges": "Zugeordnete Rand verwalten",  
583 - "unassign-dashboard-from-edge-text": "Nach der Bestätigung wird die Zuordnung des Dashboards aufgehoben und es ist für der Rand nicht mehr zugänglich.",  
584 - "assigned-edges": "Zugeordnete Rand",  
585 - "unassign-from-edge": "Zuordnung von Rand aufheben",  
586 - "unassign-dashboards-from-edge-action-title": "Zuordnung { count, plural, 1 {1 Dashboard} other {# Dashboards} } vom Rand aufheben",  
587 - "unassign-dashboards-from-edge-text": "Nach der Bestätigung wird die Zuordnung aller ausgewählten Dashboards aufgehoben und sie sind für den Rand nicht mehr zugänglich.",  
588 - "assign-dashboard-to-edge": "Dashboard(s) dem Rand zuordnen",  
589 - "assign-dashboard-to-edge-text": "Bitte wählen Sie die Dashboards aus, die Sie dem Rand zuordnen möchten",  
590 - "assign-dashboards-to-edge-text": "Zuordnen { count, plural, 1 {1 Dashboard} other {# Dashboards} } zum Rand",  
591 - "unassign-dashboards-from-edge-action-text": "Zuordnung { count, plural, 1 {1 Dashboard} other {# Dashboards} } vom Rand aufheben",  
592 - "assign-to-edges": "Dashboard(s) den Rand zuordnen",  
593 - "assign-to-edges-text": "Bitte wählen Sie den Rand aus, dem die Dashboards zugeordnet werden sollen",  
594 - "unassign-from-edges": "Zuordnung von Dashboard(s) zum Rand aufheben",  
595 - "unassign-from-edges-text": "Bitte wählen Sie die Rand aus, für die die Zuordnung von Dashboard(s) aufgehoben werden soll" 564 + "state-controller": "Zustandssteuerung"
596 }, 565 },
597 "datakey": { 566 "datakey": {
598 "settings": "Einstellungen", 567 "settings": "Einstellungen",
@@ -723,92 +692,11 @@ @@ -723,92 +692,11 @@
723 "is-gateway": "Ist ein Gateway", 692 "is-gateway": "Ist ein Gateway",
724 "public": "Öffentlich", 693 "public": "Öffentlich",
725 "device-public": "Gerät ist öffentlich", 694 "device-public": "Gerät ist öffentlich",
726 - "select-device": "Gerät auswählen",  
727 - "assign-device-to-edge": "Dashboard(s) dem Gerät zuordnen",  
728 - "assign-device-to-edge-text":"Bitte wählen Sie die Geräte aus, die Sie dem Rand zuordnen möchten",  
729 - "unassign-from-edge": "Zuordnung von Rand aufheben",  
730 - "assign-to-edge": "Einem Rand zuordnen",  
731 - "assign-to-edge-text": "Bitte wählen Sie die Geräte aus, die Sie dem Rand zuordnen möchten",  
732 - "unassign-device-from-edge-title": "Sind Sie sicher, dass Sie die Zuordnung zum Gerät '{{deviceName}}' wirklich aufheben möchten?",  
733 - "unassign-device-from-edge-text": "Nach der Bestätigung ist das Gerät nicht zugeordnet und für den Kunden nicht zugänglich.",  
734 - "unassign-devices-from-edge-action-title": "Zuordnung { count, plural, 1 {1 Gerät} other {# Geräte} } vom Rand aufheben",  
735 - "unassign-device-from-edge": "Nicht zugeordnete Geräte",  
736 - "unassign-devices-from-edge-title": "Sind Sie sicher, dass Sie { count, plural, 1 {1 Gerät} other {# Geräte} } nicht mehr zuordnen möchten?",  
737 - "unassign-devices-from-edge-text": "Nach der Bestätigung werden alle ausgewählten Geräte nicht zugewiesen und sind für den Rand nicht zugänglich." 695 + "select-device": "Gerät auswählen"
738 }, 696 },
739 "dialog": { 697 "dialog": {
740 "close": "Dialog schließen" 698 "close": "Dialog schließen"
741 }, 699 },
742 - "edge": {  
743 - "edge": "Rand",  
744 - "edges": "Rand",  
745 - "management": "Rand verwalten",  
746 - "no-edges-matching": "Keine passenden Rand '{{entity}}' gefunden.",  
747 - "add": "Rand hinzufügen",  
748 - "view": "Rand anzeigen",  
749 - "no-edges-text": "Kein Rand gefunden.",  
750 - "edge-details": "Details der Rand",  
751 - "add-edge-text": "Neue Rand hinzufügen",  
752 - "delete": "Rand löschen",  
753 - "delete-edges": "Rand löschen",  
754 - "delete-edge-title": "Möchten Sie des Rands wirklich löschen '{{edgeName}}'?",  
755 - "delete-edge-text": "Seien Sie vorsichtig, nach der Bestätigung werden der Rand und alle zugehörigen Daten nicht wiederhergestellt.",  
756 - "delete-edges-title": "Sind Sie sicher, dass Sie die Rand löschen möchten { count, plural, 1 {1 Rand} other {# Rand} }?",  
757 - "delete-edges-action-title": "Löschen { count, plural, 1 {1 Rand} other {# Rand} }",  
758 - "delete-edges-text": "Vorsicht, nach Bestätigung werden alle ausgewählten Rand entfernt und alle zugehörigen Daten werden nicht wiederhergestellt.",  
759 - "name": "Name",  
760 - "name-required": "Name ist erforderlich.",  
761 - "description": "Beschreibung",  
762 - "events": "Ereignisse",  
763 - "details": "Details",  
764 - "copy-id": "Regelketten-ID kopieren",  
765 - "id-copied-message": "Regelketten-ID wurde in die Zwischenablage kopiert",  
766 - "permissions": "Berechtigungen",  
767 - "edge-required": "Rand ist erforderlich.",  
768 - "edge-type": "Randtyp",  
769 - "edge-type-required": "Randtyp ist erforderlich.",  
770 - "select-edge-type": "Randtyp auswählen",  
771 - "assign-to-customer": "Einem Kunden zuordnen",  
772 - "assign-to-customer-text": "Bitte wählen Sie den Kunden aus, dem die Rand zugeordnet werden sollen",  
773 - "assign-edge-to-customer": "Rand dem Kunden zuordnen",  
774 - "assign-edge-to-customer-text": "Bitte wählen Sie die Rand aus, die dem Kunden zugeordnet werden sollen",  
775 - "assigned-to-customer": "Kunden Zuordnung",  
776 - "unassign-from-customer": "Kunden Zuordnung aufgehoben",  
777 - "assign-edges-text": "{ count, plural, 1 {1 Gerät} other {# Geräte} } dem Rand zuordnen",  
778 - "unassign-edge-title": "Sind Sie sicher, dass Sie die Zuordnung zum Rand '{{edgeName}}' wirklich aufheben möchten?",  
779 - "unassign-edge-text": "Nach der Bestätigung ist der Rand nicht zugeordnet und für den Kunden nicht zugänglich.",  
780 - "make-public": "Rand öffentlich machen",  
781 - "make-public-edge-title": "Sind Sie sicher, dass Sie der Rand '{{edgeName}}' öffentlich machen möchten?",  
782 - "make-public-edge-text": "Nach Bestätigung wird der Rabd und alle zugehörigen Daten anderen zugänglich gemacht.",  
783 - "make-private": "Rand privat machen",  
784 - "public": "Öffentlich",  
785 - "make-private-edge-title": "Sind Sie sicher, dass Sie der Rand '{{edgeName}}' privat machen möchten?",  
786 - "make-private-edge-text": "Nach der Bestätigung werden der Rand und dessen Daten privat und sind für andere nicht mehr zugänglich.",  
787 - "import": "Rand importieren",  
788 - "label": "Bezeichnung",  
789 - "assign-new-edge": "Neue Rand zuordnen",  
790 - "manage-edge-dashboards": "Rand-Dashboards verwalten",  
791 - "unassign-from-edge": "Zuordnung zum Rand aufheben",  
792 - "dashboards": "Rand Dashboards",  
793 - "manage-edge-rulechains": "Randregelkette verwalten",  
794 - "rulechains": "Rand Regelketten",  
795 - "rulechain": "Rand Regelkette",  
796 - "edge-key": "Rand Schlüssel",  
797 - "copy-edge-key": "Rand Schlüssel kopieren",  
798 - "edge-key-copied-message": "Rand Schlüssel wurde in die Zwischenablage kopiert",  
799 - "edge-secret": "Rand Geheimnis",  
800 - "copy-edge-secret": "Rand Geheimnis kopieren",  
801 - "edge-secret-copied-message": "Rand Geheimnis wurde in die Zwischenablage kopiert",  
802 - "manage-edge-assets": "Rand-Objekte verwalten",  
803 - "manage-edge-devices": "Rand-Geräte verwalten",  
804 - "manage-edge-entity-views": "Rand-Entitätsansichten verwalten",  
805 - "assets": "Rand Objekte",  
806 - "devices": "Objekte Geräte",  
807 - "entity-views": "Objekte Entitätsansichten",  
808 - "set-root-rule-chain-text": "Bitte wählen Sie die Regelkette zur Wurzel rule chain für die Rand",  
809 - "set-root-rule-chain-to-edges": "Regelkette zur Wurzel machen für die Rand",  
810 - "set-root-rule-chain-to-edges-text": "Die Regelkette zur Wurzel für { count, plural, 1 {1 Rand} other {# Rand} } machen"  
811 - },  
812 "error": { 700 "error": {
813 "unable-to-connect": "Es konnte keine Verbindung zum Server hergestellt werden! Bitte überprüfen Sie Ihre Internetverbindung.", 701 "unable-to-connect": "Es konnte keine Verbindung zum Server hergestellt werden! Bitte überprüfen Sie Ihre Internetverbindung.",
814 "unhandled-error-code": "Unbehandelter Fehlercode: {{errorCode}}", 702 "unhandled-error-code": "Unbehandelter Fehlercode: {{errorCode}}",
@@ -902,10 +790,6 @@ @@ -902,10 +790,6 @@
902 "type-rulenodes": "Regelknoten", 790 "type-rulenodes": "Regelknoten",
903 "list-of-rulenodes": "{ count, plural, 1 {Ein Regelknoten} other {Liste von # Regelknoten} }", 791 "list-of-rulenodes": "{ count, plural, 1 {Ein Regelknoten} other {Liste von # Regelknoten} }",
904 "rulenode-name-starts-with": "Regelknoten beginnend mit '{{prefix}}'", 792 "rulenode-name-starts-with": "Regelknoten beginnend mit '{{prefix}}'",
905 - "type-edge": "Randtyp",  
906 - "type-edges": "Randtyp",  
907 - "list-of-edges": "{ count, plural, 1 {1 Rand} other {# Rand} }",  
908 - "edge-name-starts-with": "Rand beginnend mit '{{prefix}}'",  
909 "type-current-customer": "Aktueller Kunde", 793 "type-current-customer": "Aktueller Kunde",
910 "search": "Entitäten suchen", 794 "search": "Entitäten suchen",
911 "selected-entities": "{ count, plural, 1 {Entität} other {# Entitäten} } ausgewählt", 795 "selected-entities": "{ count, plural, 1 {Entität} other {# Entitäten} } ausgewählt",
@@ -978,17 +862,6 @@ @@ -978,17 +862,6 @@
978 "entity-view-types": "Entitätsansichtstypen", 862 "entity-view-types": "Entitätsansichtstypen",
979 "name": "Name", 863 "name": "Name",
980 "name-required": "Name ist erforderlich.", 864 "name-required": "Name ist erforderlich.",
981 - "assign-entity-view-to-edge": "Entitätsansicht dem Rand zuordnen",  
982 - "assign-entity-view-to-edge-text":"Bitte wählen Sie die Entitätsansicht aus, die dem Rand zugeordnet werden sollen",  
983 - "unassign-from-edge": "Randzuordnung aufheben",  
984 - "assign-to-edge": "Einem Rand zuordnen",  
985 - "assign-to-edge-text": "Bitte wählen Sie die Entitätsansichte aus, die dem Rand zugeordnet werden sollen",  
986 - "unassign-entity-view-from-edge-title": "Sind Sie sicher, dass Sie die Zuordnung für Entitätsansicht '{{entityViewName}}' aufheben möchten?",  
987 - "unassign-entity-view-from-edge-text": "Nach Bestätigung wird die Zuordnung des Entitätsansichts aufgehoben und es ist für den Kunden nicht mehr zugänglich.",  
988 - "unassign-entity-views-from-edge-action-title": "Rand { count, plural, 1 {1 Entitätsansicht} other {# Entitätsansichte} } aufheben",  
989 - "unassign-entity-view-from-edge": "Entitätsansichtzuordnung aufheben",  
990 - "unassign-entity-views-from-edge-title": "Sind Sie sicher, dass Sie { count, plural, 1 {1 Entitätsansicht} other {# Entitätsansichte} } nicht mehr zuordnen möchten?",  
991 - "unassign-entity-views-from-edge-text": "Nach der Bestätigung werden alle ausgewählten Entitätsansicht nicht zugewiesen und sind für den Rand nicht zugänglich.",  
992 "description": "Beschreibung", 865 "description": "Beschreibung",
993 "events": "Ereignisse", 866 "events": "Ereignisse",
994 "details": "Details", 867 "details": "Details",
@@ -1352,8 +1225,6 @@ @@ -1352,8 +1225,6 @@
1352 "rulechain": { 1225 "rulechain": {
1353 "rulechain": "Regelkette", 1226 "rulechain": "Regelkette",
1354 "rulechains": "Regelketten", 1227 "rulechains": "Regelketten",
1355 - "core-rulechains": "Kernregelketten",  
1356 - "edge-rulechains": "Randregelketten",  
1357 "root": "Wurzel", 1228 "root": "Wurzel",
1358 "delete": "Regelkette löschen", 1229 "delete": "Regelkette löschen",
1359 "name": "Name", 1230 "name": "Name",
@@ -1386,40 +1257,7 @@ @@ -1386,40 +1257,7 @@
1386 "no-rulechains-matching": "Es wurden keine passenden Regelketten für '{{entity}}' gefunden.", 1257 "no-rulechains-matching": "Es wurden keine passenden Regelketten für '{{entity}}' gefunden.",
1387 "rulechain-required": "Regelkette ist erforderlich", 1258 "rulechain-required": "Regelkette ist erforderlich",
1388 "management": "Regelverwaltung", 1259 "management": "Regelverwaltung",
1389 - "debug-mode": "Modus zur Fehlersuche",  
1390 - "assign-rulechains": "Regelketten zuweisen",  
1391 - "assign-new-rulechain": "Neues Regelkette zuweisen",  
1392 - "delete-rulechains": "Regelketten löschen",  
1393 - "default": "Standard",  
1394 - "unassign-rulechain": "Nicht zugeordnete Regelkette",  
1395 - "unassign-rulechains": "Nicht zugeordnete Regelketten",  
1396 - "unassign-rulechain-title": "Möchten Sie die Zuordnung die Regelkette '{{ruleChainTitle}}' wirklich aufheben?",  
1397 - "unassign-rulechains-title": "Sind Sie sicher, dass Sie die Zuordnung aufheben möchten { count, plural, 1 {1 Regelkette} other {# Regelketten} }?",  
1398 - "manage-assigned-edges": "Zugeordnete Rand verwalten",  
1399 - "unassign-rulechain-from-edge-text": "Nach der Bestätigung wird die Zuordnung aller ausgewählten Regelkette aufgehoben und sie sind für den Rand nicht mehr zugänglich.",  
1400 - "assigned-edges": "Zugeordnete Rand",  
1401 - "unassign-from-edge": "Randzuordnung aufheben",  
1402 - "unassign-rulechains-from-edge-action-title": "Zuordnung { count, plural, 1 {1 Regelkette} other {# Regelketten} } vom Rand aufheben",  
1403 - "unassign-rulechains-from-edge-text": "Nach der Bestätigung wird die Zuordnung aller ausgewählten Regelketten aufgehoben und sie sind für den Rand nicht mehr zugänglich.",  
1404 - "assign-rulechains-to-edge-text": "Zuordnen { count, plural, 1 {1 Regelkette} other {# Regelketten} } zum Rand",  
1405 - "assign-rulechain-to-edge": "Regelkette(n) dem Rand zuordnen",  
1406 - "assign-rulechain-to-edge-text": "Bitte wählen Sie die Regelketten aus, die Sie dem Rand zuordnen möchten",  
1407 - "unassign-rulechains-from-edge-action-text": "Zuordnung { count, plural, 1 {1 Regelkette} other {# Regelketten} } vom Rand aufheben",  
1408 - "assign-to-edges": "Regelkette(n) den Rand zuordnen",  
1409 - "assign-to-edges-text": "Zuordnung von Regelkette(n) zum Rand aufheben",  
1410 - "unassign-from-edges": "Unassign Rule Chain(s) From Edges",  
1411 - "unassign-from-edges-text": "Bitte wählen Sie die Rand aus, für die die Zuordnung von Regelkette(n) aufgehoben werden soll",  
1412 - "assigned-to-edges": "Regelketten Zuordnung",  
1413 - "set-default-root-edge": "Machen Sie Randregelkette zur Wurzel Standard",  
1414 - "set-default-root-edge-rulechain-title": "Sind Sie sicher, dass Sie die Randregelkette '{{ruleChainName}}' zur Wurzel machen Standard?",  
1415 - "set-default-root-edge-rulechain-text": "Nach der Bestätigung wird die Randregelkette zur Wurzel Standard und behandelt alle eingehenden Transportnachrichten.",  
1416 - "invalid-rulechain-type-error": "Regelkette konnte nicht importiert werden: Ungültige Regelkettentyp. Erwarteter Typ ist {{expectedRuleChainType}}.",  
1417 - "set-default-edge": "Machen Sie Regelkette Standard",  
1418 - "set-default-edge-title": "Sind Sie sicher, dass Sie die Randregelkette '{{ruleChainName}}' machen Standard?",  
1419 - "set-default-edge-text": "Nach der Bestätigung wird die Randregelkette für neu erstellte Rand vergeben.",  
1420 - "remove-default-edge": "Randregelkette Standard entfernen",  
1421 - "remove-default-edge-title": "Sind Sie sicher, dass Sie die Randregelkette '{{ruleChainName}}' aus der Standardliste entfernen?",  
1422 - "remove-default-edge-text": "Nach der Bestätigung wird die Randregelkette nicht für neu erstellte Rand vergeben." 1260 + "debug-mode": "Modus zur Fehlersuche"
1423 }, 1261 },
1424 "rulenode": { 1262 "rulenode": {
1425 "details": "Details", 1263 "details": "Details",
@@ -203,8 +203,6 @@ @@ -203,8 +203,6 @@
203 "filter-type-entity-view-type": "Entity View type", 203 "filter-type-entity-view-type": "Entity View type",
204 "filter-type-entity-view-type-description": "Entity Views of type '{{entityView}}'", 204 "filter-type-entity-view-type-description": "Entity Views of type '{{entityView}}'",
205 "filter-type-entity-view-type-and-name-description": "Entity Views of type '{{entityView}}' and with name starting with '{{prefix}}'", 205 "filter-type-entity-view-type-and-name-description": "Entity Views of type '{{entityView}}' and with name starting with '{{prefix}}'",
206 - "filter-type-edge-type": "Edge type",  
207 - "filter-type-edge-type-description": "Edges of type '{{edgeType}}'",  
208 "filter-type-relations-query": "Relations query", 206 "filter-type-relations-query": "Relations query",
209 "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}", 207 "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
210 "filter-type-asset-search-query": "Asset search query", 208 "filter-type-asset-search-query": "Asset search query",
@@ -213,8 +211,6 @@ @@ -213,8 +211,6 @@
213 "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", 211 "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
214 "filter-type-entity-view-search-query": "Entity view search query", 212 "filter-type-entity-view-search-query": "Entity view search query",
215 "filter-type-entity-view-search-query-description": "Entity views with types {{entityViewTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", 213 "filter-type-entity-view-search-query-description": "Entity views with types {{entityViewTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
216 - "filter-type-edge-search-query": "Edge search query",  
217 - "filter-type-edge-search-query-description": "Edges with types {{edgeTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",  
218 "entity-filter": "Entity filter", 214 "entity-filter": "Entity filter",
219 "resolve-multiple": "Resolve as multiple entities", 215 "resolve-multiple": "Resolve as multiple entities",
220 "filter-type": "Filter type", 216 "filter-type": "Filter type",
@@ -296,20 +292,9 @@ @@ -296,20 +292,9 @@
296 "name-starts-with": "Asset name starts with", 292 "name-starts-with": "Asset name starts with",
297 "import": "Import assets", 293 "import": "Import assets",
298 "asset-file": "Asset file", 294 "asset-file": "Asset file",
299 - "search": "Search assets", 295 + "search": "Search assets",
300 "selected-assets": "{ count, plural, 1 {1 asset} other {# assets} } selected", 296 "selected-assets": "{ count, plural, 1 {1 asset} other {# assets} } selected",
301 - "label": "Label",  
302 - "assign-asset-to-edge": "Assign Asset(s) To Edge",  
303 - "assign-asset-to-edge-text":"Please select the assets to assign to the edge",  
304 - "unassign-from-edge": "Unassign from edge",  
305 - "assign-to-edge": "Assign to edge",  
306 - "assign-to-edge-text": "Please select the edge to assign the asset(s)",  
307 - "unassign-asset-from-edge": "Unassign asset",  
308 - "unassign-asset-from-edge-title": "Are you sure you want to unassign the asset '{{assetName}}'?",  
309 - "unassign-asset-from-edge-text": "After the confirmation the asset will be unassigned and won't be accessible by the edge.",  
310 - "unassign-assets-from-edge-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from edge",  
311 - "unassign-assets-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 asset} other {# assets} }?",  
312 - "unassign-assets-from-edge-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the edge." 297 + "label": "Label"
313 }, 298 },
314 "attribute": { 299 "attribute": {
315 "attributes": "Attributes", 300 "attributes": "Attributes",
@@ -359,8 +344,6 @@ @@ -359,8 +344,6 @@
359 "type-credentials-updated": "Credentials updated", 344 "type-credentials-updated": "Credentials updated",
360 "type-assigned-to-customer": "Assigned to Customer", 345 "type-assigned-to-customer": "Assigned to Customer",
361 "type-unassigned-from-customer": "Unassigned from Customer", 346 "type-unassigned-from-customer": "Unassigned from Customer",
362 - "type-assigned-to-edge": "Assigned to Edge",  
363 - "type-unassigned-from-edge": "Unassigned from Edge",  
364 "type-activated": "Activated", 347 "type-activated": "Activated",
365 "type-suspended": "Suspended", 348 "type-suspended": "Suspended",
366 "type-credentials-read": "Credentials read", 349 "type-credentials-read": "Credentials read",
@@ -425,8 +408,8 @@ @@ -425,8 +408,8 @@
425 "public-dashboards": "Public Dashboards", 408 "public-dashboards": "Public Dashboards",
426 "public-devices": "Public Devices", 409 "public-devices": "Public Devices",
427 "public-assets": "Public Assets", 410 "public-assets": "Public Assets",
428 - "public-entity-views": "Public Entity Views",  
429 "public-edges": "Public Edges", 411 "public-edges": "Public Edges",
  412 + "public-entity-views": "Public Entity Views",
430 "add": "Add Customer", 413 "add": "Add Customer",
431 "delete": "Delete customer", 414 "delete": "Delete customer",
432 "manage-customer-users": "Manage customer users", 415 "manage-customer-users": "Manage customer users",
@@ -435,9 +418,7 @@ @@ -435,9 +418,7 @@
435 "manage-public-devices": "Manage public devices", 418 "manage-public-devices": "Manage public devices",
436 "manage-public-dashboards": "Manage public dashboards", 419 "manage-public-dashboards": "Manage public dashboards",
437 "manage-customer-assets": "Manage customer assets", 420 "manage-customer-assets": "Manage customer assets",
438 - "manage-customer-edges": "Manage customer edges",  
439 "manage-public-assets": "Manage public assets", 421 "manage-public-assets": "Manage public assets",
440 - "manage-public-edges": "Manage public edges",  
441 "add-customer-text": "Add new customer", 422 "add-customer-text": "Add new customer",
442 "no-customers-text": "No customers found", 423 "no-customers-text": "No customers found",
443 "customer-details": "Customer details", 424 "customer-details": "Customer details",
@@ -464,8 +445,7 @@ @@ -464,8 +445,7 @@
464 "default-customer": "Default customer", 445 "default-customer": "Default customer",
465 "default-customer-required": "Default customer is required in order to debug dashboard on Tenant level", 446 "default-customer-required": "Default customer is required in order to debug dashboard on Tenant level",
466 "search": "Search customers", 447 "search": "Search customers",
467 - "selected-customers": "{ count, plural, 1 {1 customer} other {# customers} } selected",  
468 - "edges": "Customer Edges" 448 + "selected-customers": "{ count, plural, 1 {1 customer} other {# customers} } selected"
469 }, 449 },
470 "datetime": { 450 "datetime": {
471 "date-from": "Date from", 451 "date-from": "Date from",
@@ -618,21 +598,7 @@ @@ -618,21 +598,7 @@
618 "select-state": "Select target state", 598 "select-state": "Select target state",
619 "state-controller": "State controller", 599 "state-controller": "State controller",
620 "search": "Search dashboards", 600 "search": "Search dashboards",
621 - "selected-dashboards": "{ count, plural, 1 {1 dashboard} other {# dashboards} } selected",  
622 - "manage-assigned-edges": "Manage assigned edges",  
623 - "unassign-dashboard-from-edge-text": "After the confirmation the dashboard will be unassigned and won't be accessible by the edge.",  
624 - "assigned-edges": "Assigned edges",  
625 - "unassign-from-edge": "Unassign from edge",  
626 - "unassign-dashboards-from-edge-action-title": "Unassign { count, plural, 1 {1 dashboard} other {# dashboards} } from edge",  
627 - "unassign-dashboards-from-edge-text": "After the confirmation all selected dashboards will be unassigned and won't be accessible by the edge.",  
628 - "assign-dashboard-to-edge": "Assign Dashboard(s) To Edge",  
629 - "assign-dashboard-to-edge-text": "Please select the dashboards to assign to the edge",  
630 - "assign-dashboards-to-edge-text": "Assign { count, plural, 1 {1 dashboard} other {# dashboards} } to edges",  
631 - "unassign-dashboards-from-edge-action-text": "Unassign { count, plural, 1 {1 dashboard} other {# dashboards} } from edges",  
632 - "assign-to-edges": "Assign Dashboard(s) To Edges",  
633 - "assign-to-edges-text": "Please select the edges to assign the dashboard(s)",  
634 - "unassign-from-edges": "Unassign Dashboard(s) From Edges",  
635 - "unassign-from-edges-text": "Please select the edges to unassign from the dashboard(s)" 601 + "selected-dashboards": "{ count, plural, 1 {1 dashboard} other {# dashboards} } selected"
636 }, 602 },
637 "datakey": { 603 "datakey": {
638 "settings": "Settings", 604 "settings": "Settings",
@@ -771,18 +737,7 @@ @@ -771,18 +737,7 @@
771 "import": "Import device", 737 "import": "Import device",
772 "device-file": "Device file", 738 "device-file": "Device file",
773 "search": "Search devices", 739 "search": "Search devices",
774 - "selected-devices": "{ count, plural, 1 {1 device} other {# devices} } selected",  
775 - "assign-device-to-edge": "Assign Device(s) To Edge",  
776 - "assign-device-to-edge-text":"Please select the devices to assign to the edge",  
777 - "unassign-from-edge": "Unassign from edge",  
778 - "assign-to-edge": "Assign to edge",  
779 - "assign-to-edge-text": "Please select the edge to assign the device(s)",  
780 - "unassign-device-from-edge-title": "Are you sure you want to unassign the device '{{deviceName}}'?",  
781 - "unassign-device-from-edge-text": "After the confirmation the device will be unassigned and won't be accessible by the edge.",  
782 - "unassign-devices-from-edge-action-title": "Unassign { count, plural, 1 {1 device} other {# devices} } from edge",  
783 - "unassign-device-from-edge": "Unassign device",  
784 - "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 device} other {# devices} }?",  
785 - "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge." 740 + "selected-devices": "{ count, plural, 1 {1 device} other {# devices} } selected"
786 }, 741 },
787 "dialog": { 742 "dialog": {
788 "close": "Close dialog" 743 "close": "Close dialog"
@@ -792,74 +747,77 @@ @@ -792,74 +747,77 @@
792 "row": "Row" 747 "row": "Row"
793 }, 748 },
794 "edge": { 749 "edge": {
795 - "edge": "Edge",  
796 - "edges": "Edges",  
797 - "management": "Edge management",  
798 - "no-edges-matching": "No edges matching '{{entity}}' were found.",  
799 - "add": "Add Edge",  
800 - "view": "View Edge",  
801 - "no-edges-text": "No edges found",  
802 - "edge-details": "Edge details",  
803 - "add-edge-text": "Add new edge",  
804 - "delete": "Delete edge",  
805 - "delete-edges": "Delete edges",  
806 - "delete-edge-title": "Are you sure you want to delete the edge '{{edgeName}}'?",  
807 - "delete-edge-text": "Be careful, after the confirmation the edge and all related data will become unrecoverable.",  
808 - "delete-edges-title": "Are you sure you want to edge { count, plural, 1 {1 edge} other {# edges} }?",  
809 - "delete-edges-action-title": "Delete { count, plural, 1 {1 edge} other {# edges} }",  
810 - "delete-edges-text": "Be careful, after the confirmation all selected edges will be removed and all related data will become unrecoverable.",  
811 - "name": "Name",  
812 - "name-required": "Name is required.",  
813 - "description": "Description",  
814 - "events": "Events",  
815 - "details": "Details",  
816 - "copy-id": "Copy Edge Id",  
817 - "id-copied-message": "Edge Id has been copied to clipboard",  
818 - "permissions": "Permissions",  
819 - "edge-required": "Edge required",  
820 - "edge-type": "Edge type",  
821 - "edge-type-required": "Edge type is required.",  
822 - "select-edge-type": "Select edge type",  
823 - "assign-to-customer": "Assign to customer",  
824 - "assign-to-customer-text": "Please select the customer to assign the edge(s)",  
825 - "assign-edge-to-customer": "Assign Edge(s) To Customer",  
826 - "assign-edge-to-customer-text": "Please select the edges to assign to the customer",  
827 - "assigned-to-customer": "Assigned to customer",  
828 - "unassign-from-customer": "Unassign from customer",  
829 - "assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer",  
830 - "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?",  
831 - "unassign-edge-text": "After the confirmation the edge will be unassigned and won't be accessible by the customer.",  
832 - "make-public": "Make edge public",  
833 - "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?",  
834 - "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.",  
835 - "make-private": "Make edge private",  
836 - "public": "Public",  
837 - "make-private-edge-title": "Are you sure you want to make the edge '{{edgeName}}' private?",  
838 - "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.",  
839 - "import": "Import edge",  
840 - "label": "Label",  
841 - "assign-new-edge": "Assign new edge",  
842 - "manage-edge-dashboards": "Manage edge dashboards",  
843 - "unassign-from-edge": "Unassign from edge",  
844 - "dashboards": "Edge Dashboards",  
845 - "manage-edge-rulechains": "Manage edge rule chains",  
846 - "rulechains": "Edge Rule Chains",  
847 - "rulechain": "Edge Rule Chain",  
848 - "edge-key": "Edge key",  
849 - "copy-edge-key": "Copy edge key",  
850 - "edge-key-copied-message": "Edge key has been copied to clipboard",  
851 - "edge-secret": "Edge secret",  
852 - "copy-edge-secret": "Copy edge secret",  
853 - "edge-secret-copied-message": "Edge secret has been copied to clipboard",  
854 - "manage-edge-assets": "Manage edge assets",  
855 - "manage-edge-devices": "Manage edge devices",  
856 - "manage-edge-entity-views": "Manage edge entity views",  
857 - "assets": "Edge assets",  
858 - "devices": "Edge devices",  
859 - "entity-views": "Edge entity views",  
860 - "set-root-rule-chain-text": "Please select root rule chain for edge(s)",  
861 - "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)",  
862 - "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }" 750 + "edge": "Edge",
  751 + "edges": "Edges",
  752 + "management": "Edge management",
  753 + "no-edges-matching": "No edges matching '{{entity}}' were found.",
  754 + "add": "Add Edge",
  755 + "view": "View Edge",
  756 + "no-edges-text": "No edges found",
  757 + "edge-details": "Edge details",
  758 + "add-edge-text": "Add new edge",
  759 + "delete": "Delete edge",
  760 + "delete-edges": "Delete edges",
  761 + "delete-edge-title": "Are you sure you want to delete the edge '{{edgeName}}'?",
  762 + "delete-edge-text": "Be careful, after the confirmation the edge and all related data will become unrecoverable.",
  763 + "delete-edges-title": "Are you sure you want to edge { count, plural, 1 {1 edge} other {# edges} }?",
  764 + "delete-edges-action-title": "Delete { count, plural, 1 {1 edge} other {# edges} }",
  765 + "delete-edges-text": "Be careful, after the confirmation all selected edges will be removed and all related data will become unrecoverable.",
  766 + "name": "Name",
  767 + "name-required": "Name is required.",
  768 + "description": "Description",
  769 + "events": "Events",
  770 + "details": "Details",
  771 + "copy-id": "Copy Edge Id",
  772 + "id-copied-message": "Edge Id has been copied to clipboard",
  773 + "permissions": "Permissions",
  774 + "edge-required": "Edge required",
  775 + "edge-type": "Edge type",
  776 + "edge-type-required": "Edge type is required.",
  777 + "select-edge-type": "Select edge type",
  778 + "assign-to-customer": "Assign to customer",
  779 + "assign-to-customer-text": "Please select the customer to assign the edge(s)",
  780 + "assign-edge-to-customer": "Assign Edge(s) To Customer",
  781 + "assign-edge-to-customer-text": "Please select the edges to assign to the customer",
  782 + "assigned-to-customer": "Assigned to customer",
  783 + "unassign-from-customer": "Unassign from customer",
  784 + "assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer",
  785 + "unassign-edge-title": "Are you sure you want to unassign the edge '{{edgeName}}'?",
  786 + "unassign-edge-text": "After the confirmation the edge will be unassigned and won't be accessible by the customer.",
  787 + "make-public": "Make edge public",
  788 + "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?",
  789 + "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.",
  790 + "make-private": "Make edge private",
  791 + "public": "Public",
  792 + "make-private-edge-title": "Are you sure you want to make the edge '{{edgeName}}' private?",
  793 + "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.",
  794 + "import": "Import edge",
  795 + "label": "Label",
  796 + "assign-new-edge": "Assign new edge",
  797 + "manage-edge-dashboards": "Manage edge dashboards",
  798 + "unassign-from-edge": "Unassign from edge",
  799 + "dashboards": "Edge Dashboards",
  800 + "manage-edge-rulechains": "Manage edge rule chains",
  801 + "rulechains": "Edge Rule Chains",
  802 + "rulechain": "Edge Rule Chain",
  803 + "edge-key": "Edge key",
  804 + "copy-edge-key": "Copy edge key",
  805 + "edge-key-copied-message": "Edge key has been copied to clipboard",
  806 + "edge-secret": "Edge secret",
  807 + "copy-edge-secret": "Copy edge secret",
  808 + "edge-secret-copied-message": "Edge secret has been copied to clipboard",
  809 + "manage-edge-assets": "Manage edge assets",
  810 + "manage-edge-devices": "Manage edge devices",
  811 + "manage-edge-entity-views": "Manage edge entity views",
  812 + "assets": "Edge assets",
  813 + "devices": "Edge devices",
  814 + "entity-views": "Edge entity views",
  815 + "set-root-rule-chain-text": "Please select root rule chain for edge(s)",
  816 + "set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)",
  817 + "set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }",
  818 + "selected-edges": "{ count, plural, 1 {1 edge} other {# edges} } selected",
  819 + "name-starts-with": "Edge name starts with",
  820 + "search": "Search edges"
863 }, 821 },
864 "error": { 822 "error": {
865 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", 823 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.",
@@ -954,10 +912,6 @@ @@ -954,10 +912,6 @@
954 "type-rulenodes": "Rule nodes", 912 "type-rulenodes": "Rule nodes",
955 "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }", 913 "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }",
956 "rulenode-name-starts-with": "Rule nodes whose names start with '{{prefix}}'", 914 "rulenode-name-starts-with": "Rule nodes whose names start with '{{prefix}}'",
957 - "type-edge": "Edge",  
958 - "type-edges": "Edges",  
959 - "list-of-edges": "{ count, plural, 1 {One edge} other {List of # edges} }",  
960 - "edge-name-starts-with": "Edges whose names start with '{{prefix}}'",  
961 "type-current-customer": "Current Customer", 915 "type-current-customer": "Current Customer",
962 "type-current-tenant": "Current Tenant", 916 "type-current-tenant": "Current Tenant",
963 "search": "Search entities", 917 "search": "Search entities",
@@ -1086,18 +1040,7 @@ @@ -1086,18 +1040,7 @@
1086 "make-private-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' private?", 1040 "make-private-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' private?",
1087 "make-private-entity-view-text": "After the confirmation the entity view and all its data will be made private and won't be accessible by others.", 1041 "make-private-entity-view-text": "After the confirmation the entity view and all its data will be made private and won't be accessible by others.",
1088 "search": "Search entity views", 1042 "search": "Search entity views",
1089 - "selected-entity-views": "{ count, plural, 1 {1 entity view} other {# entity views} } selected",  
1090 - "assign-entity-view-to-edge": "Assign Entity View(s) To Edge",  
1091 - "assign-entity-view-to-edge-text":"Please select the entity views to assign to the edge",  
1092 - "unassign-from-edge": "Unassign from edge",  
1093 - "assign-to-edge": "Assign to edge",  
1094 - "assign-to-edge-text": "Please select the edge to assign the entity view(s)",  
1095 - "unassign-entity-view-from-edge-title": "Are you sure you want to unassign the entity view '{{entityViewName}}'?",  
1096 - "unassign-entity-view-from-edge-text": "After the confirmation the entity view will be unassigned and won't be accessible by the edge.",  
1097 - "unassign-entity-views-from-edge-action-title": "Unassign { count, plural, 1 {1 entity view} other {# entity views} } from edge",  
1098 - "unassign-entity-view-from-edge": "Unassign entity view",  
1099 - "unassign-entity-views-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 entity view} other {# entity views} }?",  
1100 - "unassign-entity-views-from-edge-text": "After the confirmation all selected entity views will be unassigned and won't be accessible by the edge." 1043 + "selected-entity-views": "{ count, plural, 1 {1 entity view} other {# entity views} } selected"
1101 }, 1044 },
1102 "event": { 1045 "event": {
1103 "event-type": "Event type", 1046 "event-type": "Event type",
@@ -1553,10 +1496,9 @@ @@ -1553,10 +1496,9 @@
1553 "no-relations-text": "No relations found" 1496 "no-relations-text": "No relations found"
1554 }, 1497 },
1555 "rulechain": { 1498 "rulechain": {
  1499 + "edge-rulechains": "Edge Rule chains",
1556 "rulechain": "Rule chain", 1500 "rulechain": "Rule chain",
1557 "rulechains": "Rule chains", 1501 "rulechains": "Rule chains",
1558 - "core-rulechains": "Core Rule chains",  
1559 - "edge-rulechains": "Edge Rule chains",  
1560 "root": "Root", 1502 "root": "Root",
1561 "delete": "Delete rule chain", 1503 "delete": "Delete rule chain",
1562 "name": "Name", 1504 "name": "Name",
@@ -1592,40 +1534,7 @@ @@ -1592,40 +1534,7 @@
1592 "debug-mode": "Debug mode", 1534 "debug-mode": "Debug mode",
1593 "search": "Search rule chains", 1535 "search": "Search rule chains",
1594 "selected-rulechains": "{ count, plural, 1 {1 rule chain} other {# rule chains} } selected", 1536 "selected-rulechains": "{ count, plural, 1 {1 rule chain} other {# rule chains} } selected",
1595 - "open-rulechain": "Open rule chain",  
1596 - "assign-rulechains": "Assign rulechains",  
1597 - "assign-new-rulechain": "Assign new rulechain",  
1598 - "delete-rulechains": "Delete rulechains",  
1599 - "default": "Default",  
1600 - "unassign-rulechain": "Unassign rulechain",  
1601 - "unassign-rulechains": "Unassign rulechains",  
1602 - "unassign-rulechain-title": "Are you sure you want to unassign the rulechain '{{ruleChainTitle}}'?",  
1603 - "unassign-rulechains-title": "Are you sure you want to unassign { count, plural, 1 {1 rulechain} other {# rulechains} }?",  
1604 - "manage-assigned-edges": "Manage assigned edges",  
1605 - "unassign-rulechain-from-edge-text": "After the confirmation the rulechain will be unassigned and won't be accessible by the edge.",  
1606 - "assigned-edges": "Assigned edges",  
1607 - "unassign-from-edge": "Unassign from edge",  
1608 - "unassign-rulechains-from-edge-action-title": "Unassign { count, plural, 1 {1 rulechain} other {# rulechains} } from edge",  
1609 - "unassign-rulechains-from-edge-text": "After the confirmation all selected rulechains will be unassigned and won't be accessible by the edge.",  
1610 - "assign-rulechains-to-edge-text": "Assign { count, plural, 1 {1 rulechain} other {# rulechains} } to edges",  
1611 - "assign-rulechain-to-edge": "Assign Rule Chain(s) To Edge",  
1612 - "assign-rulechain-to-edge-text": "Please select the rulechains to assign to the edge",  
1613 - "unassign-rulechains-from-edge-action-text": "Unassign { count, plural, 1 {1 rulechain} other {# rulechains} } from edges",  
1614 - "assign-to-edges": "Assign Rule Chain(s) To Edges",  
1615 - "assign-to-edges-text": "Please select the edges to assign the rulechain(s)",  
1616 - "unassign-from-edges": "Unassign Rule Chain(s) From Edges",  
1617 - "unassign-from-edges-text": "Please select the edges to unassign from the rulechain(s)",  
1618 - "assigned-to-edges": "Assigned to edges",  
1619 - "set-default-root-edge": "Make rule chain default root",  
1620 - "set-default-root-edge-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' default edge root?",  
1621 - "set-default-root-edge-rulechain-text": "After the confirmation the rule chain will become default edge root and will handle all incoming transport messages.",  
1622 - "invalid-rulechain-type-error": "Unable to import rule chain: Invalid rule chain type. Expected type is {{expectedRuleChainType}}.",  
1623 - "set-default-edge": "Make edge rule chain default",  
1624 - "set-default-edge-title": "Are you sure you want to make the edge rule chain '{{ruleChainName}}' default?",  
1625 - "set-default-edge-text": "After the confirmation the edge rule chain will be added to default list and assigned to newly created edge(s).",  
1626 - "remove-default-edge": "Remove edge rule chain from defaults",  
1627 - "remove-default-edge-title": "Are you sure you want to remove the edge rule chain '{{ruleChainName}}' from default list?",  
1628 - "remove-default-edge-text": "After the confirmation the edge rule chain will not be assigned for a newly created edges." 1537 + "open-rulechain": "Open rule chain"
1629 }, 1538 },
1630 "rulenode": { 1539 "rulenode": {
1631 "details": "Details", 1540 "details": "Details",
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 "refresh-token-failed": "No se puede actualizar la sesión" 9 "refresh-token-failed": "No se puede actualizar la sesión"
10 }, 10 },
11 "action": { 11 "action": {
12 - "activate": "Activar", 12 + "activate": "Activar",
13 "suspend": "Suspender", 13 "suspend": "Suspender",
14 "save": "Guardar", 14 "save": "Guardar",
15 "saveAs": "Guardar como", 15 "saveAs": "Guardar como",
@@ -192,8 +192,6 @@ @@ -192,8 +192,6 @@
192 "filter-type-entity-view-type": "Tipo de vista de entidad", 192 "filter-type-entity-view-type": "Tipo de vista de entidad",
193 "filter-type-entity-view-type-description": "Vistas de entidad del tipo '{{entityView}}'", 193 "filter-type-entity-view-type-description": "Vistas de entidad del tipo '{{entityView}}'",
194 "filter-type-entity-view-type-and-name-description": "Vistas de entidad del tipo '{{entityView}}' y cuyo nombre comience por '{{prefix}}'", 194 "filter-type-entity-view-type-and-name-description": "Vistas de entidad del tipo '{{entityView}}' y cuyo nombre comience por '{{prefix}}'",
195 - "filter-type-edge-type": "Tipo de borde",  
196 - "filter-type-edge-type-description": "Bordes del tipo '{{edgeType}}'",  
197 "filter-type-relations-query": "Consulta de relaciones", 195 "filter-type-relations-query": "Consulta de relaciones",
198 "filter-type-relations-query-description": "{{entities}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}", 196 "filter-type-relations-query-description": "{{entities}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}",
199 "filter-type-asset-search-query": "Búsqueda de activos", 197 "filter-type-asset-search-query": "Búsqueda de activos",
@@ -202,14 +200,10 @@ @@ -202,14 +200,10 @@
202 "filter-type-device-search-query-description": "Dispositivos con tipos {{deviceTypes}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}", 200 "filter-type-device-search-query-description": "Dispositivos con tipos {{deviceTypes}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}",
203 "filter-type-entity-view-search-query": "Consulta de búsqueda de vista de entidad", 201 "filter-type-entity-view-search-query": "Consulta de búsqueda de vista de entidad",
204 "filter-type-entity-view-search-query-description": "Vistas de entidad con tipos {{entityViewTypes}} que tienen tipo de relación {{relationType}} con dirección {{direction}} {{rootEntity}}", 202 "filter-type-entity-view-search-query-description": "Vistas de entidad con tipos {{entityViewTypes}} que tienen tipo de relación {{relationType}} con dirección {{direction}} {{rootEntity}}",
205 - "type-assigned-to-edge": "Asignado a borde",  
206 - "type-unassigned-from-edge": "Sin asignar desde bordes",  
207 "entity-filter": "Filtro por entidad", 203 "entity-filter": "Filtro por entidad",
208 "resolve-multiple": "Tomar como múltiples entidades", 204 "resolve-multiple": "Tomar como múltiples entidades",
209 "filter-type": "Filtro por tipo", 205 "filter-type": "Filtro por tipo",
210 "filter-type-required": "Se requiere filtro por tipo.", 206 "filter-type-required": "Se requiere filtro por tipo.",
211 - "filter-type-edge-type": "Tipo de borde",  
212 - "filter-type-edge-type-description": "Bordes del tipo '{{edgeType}}'",  
213 "entity-filter-no-entity-matched": "No se han encontrado entidades con el filtro especificado.", 207 "entity-filter-no-entity-matched": "No se han encontrado entidades con el filtro especificado.",
214 "no-entity-filter-specified": "No hay filtro de entidades especificado", 208 "no-entity-filter-specified": "No hay filtro de entidades especificado",
215 "root-state-entity": "Usar estado de panel como raíz", 209 "root-state-entity": "Usar estado de panel como raíz",
@@ -398,7 +392,6 @@ @@ -398,7 +392,6 @@
398 "public-devices": "Dispositivos Públicos", 392 "public-devices": "Dispositivos Públicos",
399 "public-assets": "Activos Públicos", 393 "public-assets": "Activos Públicos",
400 "public-entity-views": "Vistas de Entidad Públicas", 394 "public-entity-views": "Vistas de Entidad Públicas",
401 - "public-edge": "Bordes públicos",  
402 "add": "Agregar cliente", 395 "add": "Agregar cliente",
403 "delete": "Borrar cliente", 396 "delete": "Borrar cliente",
404 "manage-customer-users": "Gestionar usuarios del cliente", 397 "manage-customer-users": "Gestionar usuarios del cliente",
@@ -407,8 +400,6 @@ @@ -407,8 +400,6 @@
407 "manage-public-devices": "Gestionar dispositivos públicos", 400 "manage-public-devices": "Gestionar dispositivos públicos",
408 "manage-public-dashboards": "Gestionar paneles públicos", 401 "manage-public-dashboards": "Gestionar paneles públicos",
409 "manage-customer-assets": "Gestionar activos del cliente", 402 "manage-customer-assets": "Gestionar activos del cliente",
410 - "manage-customer-edge": "Administrar bordes de clientes",  
411 - "manage-public-edge": "Administrar bordes públicos",  
412 "manage-public-assets": "Gestionar activos públicos", 403 "manage-public-assets": "Gestionar activos públicos",
413 "add-customer-text": "Agregar nuevo cliente", 404 "add-customer-text": "Agregar nuevo cliente",
414 "no-customers-text": "No se encontraron clientes", 405 "no-customers-text": "No se encontraron clientes",
@@ -427,7 +418,6 @@ @@ -427,7 +418,6 @@
427 "description": "Descripción", 418 "description": "Descripción",
428 "details": "Detalles", 419 "details": "Detalles",
429 "events": "Eventos", 420 "events": "Eventos",
430 - "edge": "Bordes del cliente",  
431 "copyId": "Copiar ID de cliente", 421 "copyId": "Copiar ID de cliente",
432 "idCopiedMessage": "El ID de cliente se ha copiado al portapapeles", 422 "idCopiedMessage": "El ID de cliente se ha copiado al portapapeles",
433 "select-customer": "Seleccionar Cliente", 423 "select-customer": "Seleccionar Cliente",
@@ -582,21 +572,7 @@ @@ -582,21 +572,7 @@
582 "show-details": "Mostrar detalles", 572 "show-details": "Mostrar detalles",
583 "hide-details": "Ocultar detalles", 573 "hide-details": "Ocultar detalles",
584 "select-state": "Seleccionar estado destino (target state)", 574 "select-state": "Seleccionar estado destino (target state)",
585 - "state-controller": "Controlador de estados",  
586 - "manage-assigned-edges": "Administrar bordes asignados",  
587 - "unassign-dashboard-from-edge-text": "Después de la confirmación, el tablero no será asignado y el borde no podrá acceder a él",  
588 - "assigned-edges": "bordes asignados",  
589 - "unassign-from-edge": "Anular asignación de borde",  
590 - "unassign-dashboards-from-edge-action-title": "Anular asignación { count, plural, 1 {1 panel} other {# paneles} } de borde",  
591 - "unassign-dashboards-from-edge-text": "Después de la confirmación, se anulará la asignación de todos los paneles seleccionados y no serán accesibles por de borde",  
592 - "assign-dashboard-to-edge": "Asignar panel(es) al borde",  
593 - "assign-dashboard-to-edge-text": "Por favor selecciona los paneles para asignar al borde",  
594 - "assign-dashboards-to-edge-text": "Asignar { count, plural, 1 {1 panel} other {# paneles} } a los bordes",  
595 - "unassign-dashboards-from-edge-action-text": "Anular asignación { count, plural, 1 {1 dashboard} other {# dashboards} } de los bordes",  
596 - "assign-to-edges": "Asignar paneles a los bordes",  
597 - "assign-to-edges-text": "Seleccione los bordes para asignar los paneles",  
598 - "unassign-from-edges": "Desasignar panel (s) de los bordes",  
599 - "unassign-from-edge-text": "Seleccione los bordes para desasignar del panel(es)" 575 + "state-controller": "Controlador de estados"
600 }, 576 },
601 "datakey": { 577 "datakey": {
602 "settings": "Ajustes", 578 "settings": "Ajustes",
@@ -732,18 +708,7 @@ @@ -732,18 +708,7 @@
732 "device-public": "El dispositivo es público", 708 "device-public": "El dispositivo es público",
733 "select-device": "Seleccionar dispositivo", 709 "select-device": "Seleccionar dispositivo",
734 "device-file": "Archivo de dispositivo", 710 "device-file": "Archivo de dispositivo",
735 - "import": "Importar dispositivo",  
736 - "assign-device-to-edge": "Asignar dispositivo (s) a borde",  
737 - "assign-device-to-edge-text": "Seleccione los dispositivos para asignar al borde",  
738 - "unassign-from-edge": "Anular asignación de borde",  
739 - "assign-to-edge": "Asignar al borde",  
740 - "assign-to-edge-text": "Seleccione el borde para asignar los dispositivos",  
741 - "unassign-device-from-edge-title": "¿Está seguro de que desea desasignar el dispositivo '{{deviceName}}'?",  
742 - "unassign-device-from-edge-text": "Después de la confirmación, el dispositivo no será asignado y el borde no podrá acceder a él",  
743 - "unassign-devices-from-edge-action-title": "Anular asignación {count, plural, 1 {1 device} other {# devices}} from edge",  
744 - "unassign-device-from-edge": "Desasignar dispositivo",  
745 - "unassign-devices-from-edge-title": "¿Está seguro de que desea desasignar {count, plural, 1 {1 device} other {# devices}}?",  
746 - "unassign-devices-from-edge-text": "Después de la confirmación, todos los dispositivos seleccionados quedarán sin asignar y el borde no podrá acceder a ellos" 711 + "import": "Importar dispositivo"
747 }, 712 },
748 "dialog": { 713 "dialog": {
749 "close": "Cerrar diálogo" 714 "close": "Cerrar diálogo"
@@ -752,76 +717,6 @@ @@ -752,76 +717,6 @@
752 "column": "Columna", 717 "column": "Columna",
753 "row": "Fila" 718 "row": "Fila"
754 }, 719 },
755 - "edge": {  
756 - "edge": "Borde",  
757 - "edges": "Bordes",  
758 - "management": "Gestión de bordes",  
759 - "no-edge-matching": "No se encontraron bordes que coincidan con '{{entity}}'",  
760 - "add": "Agregar borde",  
761 - "view": "Ver borde",  
762 - "no-edge-text": "No se encontraron bordes",  
763 - "edge-details": "Detalles del borde",  
764 - "add-edge-text": "Agregar nuevo borde",  
765 - "delete": "Eliminar borde",  
766 - "delete-edges": "Eliminar bordes",  
767 - "delete-edge-title": "¿Está seguro de que desea eliminar el borde '{{edgeName}}'?",  
768 - "delete-edge-text": "Tenga cuidado, después de la confirmación, el borde y todos los datos relacionados serán irrecuperables",  
769 - "delete-edges-title": "¿Está seguro de que desea edge {count, plural, 1 {1 borde} other {# bordes}}?",  
770 - "delete-edge-action-title": "Eliminar {cuenta, plural, 1 {1 borde} otro {# bordes}}",  
771 - "delete-edges-text": "Tenga cuidado, después de la confirmación se eliminarán todos los bordes seleccionados y todos los datos relacionados se volverán irrecuperables",  
772 - "name": "Nombre",  
773 - "name-required": "Se requiere nombre",  
774 - "description": "Descripción",  
775 - "events": "Eventos",  
776 - "details": "Detalles",  
777 - "copy-id": "Copiar ID de borde",  
778 - "id-copied-message": "El ID de borde se ha copiado al portapapeles",  
779 - "permissions": "Permisos",  
780 - "edge-required": "Edge required",  
781 - "edge-type": "Type de la bordure",  
782 - "edge-type-required": "El tipo de borde es requerido.",  
783 - "select-edge-type": "Seleccionar tipo de borde",  
784 - "assign-to-customer": "Asignar al cliente",  
785 - "assign-to-customer-text": "Seleccione el cliente para asignar los bordes",  
786 - "assign-edge-to-customer": "Asignar borde(s) al cliente",  
787 - "assign-edge-to-customer-text": "Seleccione los bordes para asignar al cliente",  
788 - "assigned-to-customer": "Asignado al cliente",  
789 - "unassign-from-customer": "Anular asignación del cliente",  
790 - "assign-edges-text": "Asignar {cuenta, plural, 1 {1 borde} otro {# bordes}} al cliente",  
791 - "unassign-edge-title": "¿Está seguro de que desea desasignar el borde '{{edgeName}}'?",  
792 - "unassign-edge-text": "Después de la confirmación, el borde quedará sin asignar y el cliente no podrá acceder a él",  
793 - "make-public": "Hacer público el borde",  
794 - "make-public-edge-title": "¿Estás seguro de que quieres hacer público el edge '{{edgeName}}'?",  
795 - "make-public-edge-text": "Después de la confirmación, el borde y todos sus datos serán públicos y accesibles para otros",  
796 - "make-private": "Hacer que edge sea privado",  
797 - "public": "Public",  
798 - "make-private-edge-title": "¿Está seguro de que desea que el borde '{{edgeName}}' sea privado?",  
799 - "make-private-edge-text": "Después de la confirmación, el borde y todos sus datos se harán privados y otros no podrán acceder a ellos",  
800 - "import": "Importar borde",  
801 - "label": "Etiqueta",  
802 - "assign-new-edge": "Asignar nuevo borde",  
803 - "manage-edge-dashboards": "Administrar paneles de borde",  
804 - "unassign-from-edge": "Anular asignación de borde",  
805 - "dashboards": "Paneles de borde",  
806 - "manage-edge-rulechains": "Administrar cadenas de reglas de borde",  
807 - "rulechains": "Cadenas de regla de borde",  
808 - "rulechain": "Cadena de regla de borde",  
809 - "edge-key": "Clave de borde",  
810 - "copy-edge-key": "Copiar clave de borde",  
811 - "edge-key-copied-message": "La clave de borde se ha copiado al portapapeles",  
812 - "edge-secret": "Borde secreto",  
813 - "copy-edge-secret": "Copiar borde secreto",  
814 - "edge-secret-copied-message": "El secreto de borde se ha copiado al portapapeles",  
815 - "manage-edge-assets": "Gestionar activos de bordes",  
816 - "manage-edge-devices": "Gestionar dispositivos de borde",  
817 - "manage-edge-entity-views": "Gestionar vistas de entidad de borde",  
818 - "assets": "Activos de borde",  
819 - "devices": "Dispositivos de borde",  
820 - "entity-views": "Vistas de entidad de borde",  
821 - "set-root-rule-chain-text": "Seleccione la cadena de reglas raíz para los bordes",  
822 - "set-root-rule-chain-to-edge": "Establecer la cadena de reglas raíz para Edge (s)",  
823 - "set-root-rule-chain-to-edge-text": "Establecer la cadena de la regla raíz para {count, plural, 1 {1 borde} other {# bordes}}"  
824 - },  
825 "error": { 720 "error": {
826 "unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.", 721 "unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.",
827 "unhandled-error-code": "Código de error no controlado: {{errorCode}}", 722 "unhandled-error-code": "Código de error no controlado: {{errorCode}}",
@@ -915,10 +810,6 @@ @@ -915,10 +810,6 @@
915 "type-rulenodes": "Nodos de reglas", 810 "type-rulenodes": "Nodos de reglas",
916 "list-of-rulenodes": "{ count, plural, 1 {Un nodo de reglas} other {Lista de # nodos de reglas} }", 811 "list-of-rulenodes": "{ count, plural, 1 {Un nodo de reglas} other {Lista de # nodos de reglas} }",
917 "rulenode-name-starts-with": "Nodos de reglas cuyos nombres comienzan con '{{prefix}}'", 812 "rulenode-name-starts-with": "Nodos de reglas cuyos nombres comienzan con '{{prefix}}'",
918 - "type-edge": "Borde",  
919 - "type-edges": "Bordes",  
920 - "list-of-edges": "{cuenta, plural, 1 {Un borde} otro {Lista de # bordes}}",  
921 - "edge-name-starts-with": "Bordes cuyos nombres comienzan con '{{prefijo}}'",  
922 "type-current-customer": "Cliente Actual", 813 "type-current-customer": "Cliente Actual",
923 "type-current-tenant": "Propietario Actual", 814 "type-current-tenant": "Propietario Actual",
924 "search": "Buscar entidades", 815 "search": "Buscar entidades",
@@ -1041,18 +932,7 @@ @@ -1041,18 +932,7 @@
1041 "make-public-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea pública?", 932 "make-public-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea pública?",
1042 "make-public-entity-view-text": "Después de la confirmación, la vista de la entidad y todos sus datos se harán públicos y accesibles para otros.", 933 "make-public-entity-view-text": "Después de la confirmación, la vista de la entidad y todos sus datos se harán públicos y accesibles para otros.",
1043 "make-private-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea privada?", 934 "make-private-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea privada?",
1044 - "make-private-entity-view-text": "Después de la confirmación, la vista de la entidad y todos sus datos se harán privados y no serán accesibles para otros.",  
1045 - "assign-entity-view-to-edge": "Asignar vista (s) de entidad a borde",  
1046 - "assign-entity-view-to-edge-text": "Seleccione las vistas de entidad para asignar al borde",  
1047 - "unassign-from-edge": "Anular asignación de borde",  
1048 - "assign-to-edge": "Asignar al borde",  
1049 - "assign-to-edge-text": "Seleccione el borde para asignar las vistas de entidad",  
1050 - "unassign-entity-view-from-edge-title": "¿Está seguro de que desea anular la asignación de la vista de entidad '{{entityViewName}}'?",  
1051 - "unassign-entity-view-from-edge-text": "Después de la confirmación, la vista de entidad quedará sin asignar y el borde no podrá acceder a ella",  
1052 - "unassign-entity-views-from-edge-action-title": "Anular asignación {recuento, plural, 1 {1 vista de entidad} otras {# vistas de entidad}} del borde",  
1053 - "unassign-entity-view-from-edge": "Anular asignación de vista de entidad",  
1054 - "unassign-entity-views-from-edge-title": "¿Está seguro de que desea desasignar {count, plural, 1 {1 vista de entidad} other {# vistas de entidad}}?",  
1055 - "unassign-entity-views-from-edge-text": "Después de la confirmación, todas las vistas de entidad seleccionadas no serán asignadas y el borde no podrá acceder a ellas" 935 + "make-private-entity-view-text": "Después de la confirmación, la vista de la entidad y todos sus datos se harán privados y no serán accesibles para otros."
1056 }, 936 },
1057 "event": { 937 "event": {
1058 "event-type": "Tipo de evento", 938 "event-type": "Tipo de evento",
@@ -1514,8 +1394,6 @@ @@ -1514,8 +1394,6 @@
1514 "rulechain": { 1394 "rulechain": {
1515 "rulechain": "Cadena de Regla", 1395 "rulechain": "Cadena de Regla",
1516 "rulechains": "Cadenas de Reglas", 1396 "rulechains": "Cadenas de Reglas",
1517 - "core-rulechains": "Cadenas de reglas centrales",  
1518 - "edge-rulechains": "Cadenas de reglas de borde",  
1519 "root": "Raíz", 1397 "root": "Raíz",
1520 "delete": "Borrar cadena de reglas", 1398 "delete": "Borrar cadena de reglas",
1521 "name": "Nombre", 1399 "name": "Nombre",
@@ -1548,40 +1426,7 @@ @@ -1548,40 +1426,7 @@
1548 "no-rulechains-matching": "No se encontraron cadenas de reglas que coincidan con '{{entity}}' .", 1426 "no-rulechains-matching": "No se encontraron cadenas de reglas que coincidan con '{{entity}}' .",
1549 "rulechain-required": "Cadena de reglas requerida", 1427 "rulechain-required": "Cadena de reglas requerida",
1550 "management": "Gestión de reglas", 1428 "management": "Gestión de reglas",
1551 - "debug-mode": "Modo Debug",  
1552 - "assign-rulechains": "Asignar cadenas de reglas",  
1553 - "assign-new-rulechain": "Asignar nueva cadena de reglas",  
1554 - "delete-rulechains": "Eliminar cadenas de reglas",  
1555 - "default": "Predeterminado",  
1556 - "unassign-rulechain": "Anular asignación de cadena de reglas",  
1557 - "unassign-rulechains": "Anular asignación de cadenas de reglas",  
1558 - "unassign-rulechain-title": "¿Está seguro de que desea desasignar la cadena de reglas '{{ruleChainTitle}}'?",  
1559 - "unassign-rulechains-title": "¿Está seguro de que desea desasignar {count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas}}?",  
1560 - "manage-assigned-edges": "Gestionar bordes asignados",  
1561 - "unassign-rulechain-from-edge-text": "Después de la confirmación, la cadena de reglas quedará sin asignar y el borde no podrá acceder a ella",  
1562 - "assigned-edges": "Bordes asignados",  
1563 - "unassign-from-edge": "Anular asignación de borde",  
1564 - "unassign-rulechains-from-edge-action-title": "Anular asignación {count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas}} des bordes",  
1565 - "unassign-rulechains-from-edge-text": "Después de la confirmación, todas las cadenas de reglas seleccionadas quedarán sin asignar y el borde no podrá acceder a ellas",  
1566 - "assign-rulechains-to-edge-text": "Asignar {cuenta, plural, 1 {1 cadena de reglas} otras {# cadenas de reglas}} a las aristas",  
1567 - "assign-rulechain-to-edge": "Asignar cadena (s) de reglas a borde",  
1568 - "assign-rulechain-to-edge-text": "Seleccione las cadenas de reglas para asignar al borde",  
1569 - "unassign-rulechains-from-edge-action-text": "Anular asignación {cuenta, plural, 1 {1 cadena de reglas} otro {# cadenas de reglas}} de los bordes",  
1570 - "assign-to-edges": "Asignar cadena (s) de reglas a los bordes",  
1571 - "assign-to-edges-text": "Seleccione los bordes para asignar las cadenas de reglas",  
1572 - "unassign-from-edges": "Desasignar cadena (s) de reglas de los bordes",  
1573 - "unassign-from-edges-text": "Seleccione los bordes para desasignar de la (s) cadena (s) de reglas",  
1574 - "assigned-to-edges": "Asignado a bordes",  
1575 - "set-default-root-edge": "Hacer que la cadena de reglas sea la raíz predeterminada",  
1576 - "set-default-root-edge-rulechain-title": "¿Está seguro de que desea hacer que la cadena de reglas '{{ruleChainName}}' sea la raíz de borde predeterminada?",  
1577 - "set-default-root-edge-rulechain-text": "Después de la confirmación, la cadena de reglas se convertirá en raíz raíz predeterminada y manejará todos los mensajes de transporte entrantes",  
1578 - "invalid-rulechain-type-error": "No se puede importar la cadena de reglas: Tipo de cadena de reglas no válido. El tipo esperado es {{expectedRuleChainType}}",  
1579 - "set-default-edge": "Hacer que la cadena de reglas de borde sea predeterminada",  
1580 - "set-default-edge-title": "¿Está seguro de que desea que la cadena de reglas de borde '{{ruleChainName}}' sea predeterminada?",  
1581 - "set-default-edge-text": "Después de la confirmación, la cadena de reglas de borde se agregará a la lista predeterminada y se asignará a los bordes recién creados",  
1582 - "remove-default-edge": "Eliminar la cadena de regla de borde de los valores predeterminados",  
1583 - "remove-default-edge-title": "¿Está seguro de que desea eliminar la cadena de reglas de borde '{{ruleChainName}}' de la lista predeterminada?",  
1584 - "remove-default-edge-text": "Después de la confirmación, la cadena de reglas de borde no se asignará a los bordes recién creados" 1429 + "debug-mode": "Modo Debug"
1585 }, 1430 },
1586 "rulenode": { 1431 "rulenode": {
1587 "details": "Detalles", 1432 "details": "Detalles",
@@ -176,7 +176,7 @@ @@ -176,7 +176,7 @@
176 "entity-filter": "Filtre d'entité", 176 "entity-filter": "Filtre d'entité",
177 "entity-filter-no-entity-matched": "Aucune entité correspondant au filtre spécifié n'a été trouvée.", 177 "entity-filter-no-entity-matched": "Aucune entité correspondant au filtre spécifié n'a été trouvée.",
178 "filter-type": "Type de filtre", 178 "filter-type": "Type de filtre",
179 - "filter-type-asset-search-query": "Requête de recherche d'actifs", 179 + "filter-type-asset-search-query": "requête de recherche d'actifs",
180 "filter-type-asset-search-query-description": "Actifs de types {{assetTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", 180 "filter-type-asset-search-query-description": "Actifs de types {{assetTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
181 "filter-type-asset-type": "type d'actif", 181 "filter-type-asset-type": "type d'actif",
182 "filter-type-asset-type-and-name-description": "Actifs de type '{{assetType}}' et dont le nom commence par '{{prefix}}'", 182 "filter-type-asset-type-and-name-description": "Actifs de type '{{assetType}}' et dont le nom commence par '{{prefix}}'",
@@ -190,13 +190,9 @@ @@ -190,13 +190,9 @@
190 "filter-type-entity-name": "Nom d'entité", 190 "filter-type-entity-name": "Nom d'entité",
191 "filter-type-entity-view-search-query": "Requête de recherche vue d'entité", 191 "filter-type-entity-view-search-query": "Requête de recherche vue d'entité",
192 "filter-type-entity-view-search-query-description": "Vues d'entité avec les types {{entityViewTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", 192 "filter-type-entity-view-search-query-description": "Vues d'entité avec les types {{entityViewTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
193 - "filter-type-edge-search-query": "Requête de recherche de bordure",  
194 - "filter-type-edge-search-query-description": "Bordures de types {{edgeTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",  
195 "filter-type-entity-view-type": "Type de vue d'entité", 193 "filter-type-entity-view-type": "Type de vue d'entité",
196 "filter-type-entity-view-type-and-name-description": "Vues d'entité de type '{{entityView}}' et dont le nom commence par '{{prefix}}'", 194 "filter-type-entity-view-type-and-name-description": "Vues d'entité de type '{{entityView}}' et dont le nom commence par '{{prefix}}'",
197 "filter-type-entity-view-type-description": "Vues d'entité de type '{{entityView}}'", 195 "filter-type-entity-view-type-description": "Vues d'entité de type '{{entityView}}'",
198 - "filter-type-edge-type": "Type de la bordure",  
199 - "filter-type-edge-type-description": "Dispositifs de type '{{edgeType}}'",  
200 "filter-type-relations-query": "Interrogation des relations", 196 "filter-type-relations-query": "Interrogation des relations",
201 "filter-type-relations-query-description": "{{entities}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", 197 "filter-type-relations-query-description": "{{entities}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
202 "filter-type-required": "Le type de filtre est requis.", 198 "filter-type-required": "Le type de filtre est requis.",
@@ -260,17 +256,6 @@ @@ -260,17 +256,6 @@
260 "name": "Nom", 256 "name": "Nom",
261 "name-required": "Nom est requis.", 257 "name-required": "Nom est requis.",
262 "name-starts-with": "Le nom de l'actif commence par", 258 "name-starts-with": "Le nom de l'actif commence par",
263 - "assign-asset-to-edge": "Attribuer des actifs a la bordure",  
264 - "assign-asset-to-edge-text": "Veuillez sélectionner les actifs à attribuer a la bordure",  
265 - "unassign-from-edge": "Retirer de la bordure",  
266 - "assign-to-edge": "Attribuer a la bordure",  
267 - "assign-to-edge-text": "Veuillez sélectionner la bordure pour attribuer le ou les actifs",  
268 - "unassign-asset-from-edge": "Retirer de la bordure",  
269 - "unassign-asset-from-edge-title": "Êtes-vous sûr de vouloir retirer l'attribution de l'actif '{{assetName}}'?",  
270 - "unassign-asset-from-edge-text": "Après la confirmation, l'actif sera non attribué et ne sera pas accessible a la bordure.",  
271 - "unassign-assets-from-edge-action-title": "Retirer {count, plural, 1 {1 asset} other {# assets}} de la bordure",  
272 - "unassign-assets-from-edge-title": "Êtes-vous sûr de vouloir retirer l'attribution de {count, plural, 1 {1 asset} other {# assets}}?",  
273 - "unassign-assets-from-edge-text": "Après la confirmation, tous les actifs sélectionnés ne seront pas attribués et ne seront pas accessibles a la bordure.",  
274 "no-asset-types-matching": "Aucun type d'actif correspondant à {{entitySubtype}} n'a été trouvé. ", 259 "no-asset-types-matching": "Aucun type d'actif correspondant à {{entitySubtype}} n'a été trouvé. ",
275 "no-assets-matching": "Aucun actif correspondant à {{entity}} n'a été trouvé. ", 260 "no-assets-matching": "Aucun actif correspondant à {{entity}} n'a été trouvé. ",
276 "no-assets-text": "Aucun actif trouvé", 261 "no-assets-text": "Aucun actif trouvé",
@@ -339,8 +324,6 @@ @@ -339,8 +324,6 @@
339 "type-alarm-ack": "Acquitté", 324 "type-alarm-ack": "Acquitté",
340 "type-alarm-clear": "Effacé", 325 "type-alarm-clear": "Effacé",
341 "type-assigned-to-customer": "Attribué au client", 326 "type-assigned-to-customer": "Attribué au client",
342 - "type-assigned-to-edge": "Attribué a la bordure",  
343 - "type-unassigned-from-edge": "Non attribué de la bordure",  
344 "type-attributes-deleted": "Attributs supprimés", 327 "type-attributes-deleted": "Attributs supprimés",
345 "type-attributes-read": "Attributs lus", 328 "type-attributes-read": "Attributs lus",
346 "type-attributes-updated": "Attributs mis à jour", 329 "type-attributes-updated": "Attributs mis à jour",
@@ -424,13 +407,11 @@ @@ -424,13 +407,11 @@
424 "description": "Description", 407 "description": "Description",
425 "details": "Détails", 408 "details": "Détails",
426 "devices": "Dispositifs du client", 409 "devices": "Dispositifs du client",
427 - "edges": "Bordures du client",  
428 "entity-views": "Vues de l'entité client", 410 "entity-views": "Vues de l'entité client",
429 "events": "Événements", 411 "events": "Événements",
430 "idCopiedMessage": "L'Id du client a été copié dans le presse-papier", 412 "idCopiedMessage": "L'Id du client a été copié dans le presse-papier",
431 "manage-assets": "Gérer les actifs", 413 "manage-assets": "Gérer les actifs",
432 "manage-customer-assets": "Gérer les actifs du client", 414 "manage-customer-assets": "Gérer les actifs du client",
433 - "manage-customer-edges": "Gérer les bordures du client",  
434 "manage-customer-dashboards": "Gérer les tableaux de bord du client", 415 "manage-customer-dashboards": "Gérer les tableaux de bord du client",
435 "manage-customer-devices": "Gérer les dispositifs du client", 416 "manage-customer-devices": "Gérer les dispositifs du client",
436 "manage-customer-users": "Gérer les utilisateurs du client", 417 "manage-customer-users": "Gérer les utilisateurs du client",
@@ -439,7 +420,6 @@ @@ -439,7 +420,6 @@
439 "manage-public-assets": "Gérer les actifs publics", 420 "manage-public-assets": "Gérer les actifs publics",
440 "manage-public-dashboards": "Gérer les tableaux de bord publics", 421 "manage-public-dashboards": "Gérer les tableaux de bord publics",
441 "manage-public-devices": "Gérer les dispositifs publics", 422 "manage-public-devices": "Gérer les dispositifs publics",
442 - "manage-public-edges": "Gérer les bordures publics",  
443 "manage-users": "Gérer les utilisateurs", 423 "manage-users": "Gérer les utilisateurs",
444 "management": "Gestion des clients", 424 "management": "Gestion des clients",
445 "no-customers-matching": "Aucun client correspondant à '{{entity}} n'a été trouvé.", 425 "no-customers-matching": "Aucun client correspondant à '{{entity}} n'a été trouvé.",
@@ -448,7 +428,6 @@ @@ -448,7 +428,6 @@
448 "public-dashboards": "Tableaux de bord publics", 428 "public-dashboards": "Tableaux de bord publics",
449 "public-devices": "Dispositifs publics", 429 "public-devices": "Dispositifs publics",
450 "public-entity-views": "Vues d'entités publiques", 430 "public-entity-views": "Vues d'entités publiques",
451 - "public-edges": "Bordures publics",  
452 "select-customer": "Sélectionner un client", 431 "select-customer": "Sélectionner un client",
453 "select-default-customer": "Sélectionnez le client par défaut", 432 "select-default-customer": "Sélectionnez le client par défaut",
454 "title": "Titre", 433 "title": "Titre",
@@ -593,21 +572,7 @@ @@ -593,21 +572,7 @@
593 "view-dashboards": "Afficher les tableaux de bord", 572 "view-dashboards": "Afficher les tableaux de bord",
594 "widget-file": "Fichier du Widget", 573 "widget-file": "Fichier du Widget",
595 "widget-import-missing-aliases-title": "Configurer les alias utilisés par le widget importé", 574 "widget-import-missing-aliases-title": "Configurer les alias utilisés par le widget importé",
596 - "widgets-margins": "Marge entre les widgets",  
597 - "manage-assigned-edges": "Gérer les bordures affectés",  
598 - "unassign-dashboard-from-edge-text": "Après la confirmation, tableau de bord sera non attribué et ne sera pas accessible a la bordure.",  
599 - "assigned-edges": "Bordures affectés",  
600 - "unassign-from-edge": "Retirer de la bordure",  
601 - "unassign-dashboards-from-edge-action-title": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} de la bordure",  
602 - "unassign-dashboards-from-edge-text": "Après la confirmation, tous les tableaux de bord sélectionnés ne seront pas attribués et ne seront pas accessibles a la bordure.",  
603 - "assign-dashboard-to-edge": "Attribuer des tableaux de bord a la bordure",  
604 - "assign-dashboard-to-edge-text": "Veuillez sélectionner la bordure pour attribuer le ou les tableaux de bord",  
605 - "assign-dashboards-to-edge-text": "Attribuer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} aux bordures",  
606 - "unassign-dashboards-from-edge-action-text": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} des bordures",  
607 - "assign-to-edges": "Attribuer des tableaux de bord a la bordures",  
608 - "assign-to-edges-text": "Veuillez sélectionner les bordures pour attribuer les tableaux de bord",  
609 - "unassign-from-edges": "Retirer de la bordure",  
610 - "unassign-from-edges-text": "Veuillez sélectionner les bordures à annuler l'affectation du ou des tableaux de bord" 575 + "widgets-margins": "Marge entre les widgets"
611 }, 576 },
612 "datakey": { 577 "datakey": {
613 "advanced": "Avancé", 578 "advanced": "Avancé",
@@ -745,92 +710,11 @@ @@ -745,92 +710,11 @@
745 "unassign-from-customer": "Retirer du client", 710 "unassign-from-customer": "Retirer du client",
746 "use-device-name-filter": "Utiliser le filtre", 711 "use-device-name-filter": "Utiliser le filtre",
747 "view-credentials": "Afficher les informations d'identification", 712 "view-credentials": "Afficher les informations d'identification",
748 - "view-devices": "Afficher les dispositifs",  
749 - "assign-device-to-edge": "Attribuer a la bordure",  
750 - "assign-device-to-edge-text":"Veuillez sélectionner la bordure pour attribuer le ou les dispositifs",  
751 - "unassign-from-edge": "Retirer de la bordure",  
752 - "assign-to-edge": "Attribuer a la bordure",  
753 - "assign-to-edge-text": "Veuillez sélectionner la bordure pour attribuer le ou les dispositifs",  
754 - "unassign-device-from-edge-title": "Êtes-vous sûr de vouloir annuler l'affection du dispositif {{deviceName}} '?",  
755 - "unassign-device-from-edge-text": "Après la confirmation, dispositif sera non attribué et ne sera pas accessible a la bordure.",  
756 - "unassign-devices-from-edge-action-title": "Annuler l'affectation de {count, plural, 1 {1 device} other {#devices}} de la bordure",  
757 - "unassign-device-from-edge": "Retirer de la bordure",  
758 - "unassign-devices-from-edge-title": "Voulez-vous vraiment annuler l'affectation de {count, plural, 1 {1 device} other {# devices}}?",  
759 - "unassign-devices-from-edge-text": "Après la confirmation, tous les dispositifs sélectionnés ne seront pas attribues et ne seront pas accessibles par la bordure." 713 + "view-devices": "Afficher les dispositifs"
760 }, 714 },
761 "dialog": { 715 "dialog": {
762 "close": "Fermer le dialogue" 716 "close": "Fermer le dialogue"
763 }, 717 },
764 - "edge": {  
765 - "edge": "Bordure",  
766 - "edges": "Bordures",  
767 - "management": "Gestion des bordures",  
768 - "no-edges-matching": "Aucun bordure correspondant à {{entity}} n'a été trouvé.",  
769 - "add": "Ajouter un bordure",  
770 - "view": "Afficher la bordure",  
771 - "no-edges-text": "Aucun bordure trouvé",  
772 - "edge-details": "Détails de la bordure",  
773 - "add-edge-text": "Ajouter une nouveau bordure",  
774 - "delete": "Supprimer la bordure",  
775 - "delete-edges": "Supprimer les bordures",  
776 - "delete-edge-title": "Êtes-vous sûr de vouloir supprimer la bordure '{{edgeName}}'?",  
777 - "delete-edge-text": "Faites attention, après la confirmation, la bordure et toutes les données associées deviendront irrécupérables",  
778 - "delete-edges-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 bordure} other {# bordure}}?",  
779 - "delete-edges-action-title": "Supprimer {count, plural, 1 {1 bordure} other {# bordure}}",  
780 - "delete-edges-text": "Faites attention, après la confirmation, tous les bordures sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.",  
781 - "name": "Nom",  
782 - "name-required": "Le nom de la bordure est requis",  
783 - "description": "Dispositifs",  
784 - "events": "Événements",  
785 - "details": "Détails de l'entité",  
786 - "copy-id": "Copier borudre Id",  
787 - "id-copied-message": "Id de la bordure a été copié dans le presse-papier",  
788 - "permissions": "Autorisations",  
789 - "edge-required": "Bordure est requise",  
790 - "edge-type": "Type de la bordure",  
791 - "edge-type-required": "Type de la bordure est requise.",  
792 - "select-edge-type": "Selectionner un type de la bordure",  
793 - "assign-to-customer": "Attribuer au client",  
794 - "assign-to-customer-text": "Veuillez sélectionner la bordure pour attribuer le ou les dispositifs",  
795 - "assign-edge-to-customer": "Attribuer la bordure au client",  
796 - "assign-edge-to-customer-text": "Veuillez sélectionner la bordure pour attribuer le ou les dispositifs",  
797 - "assigned-to-customer": "Attribué au client",  
798 - "unassign-from-customer": "Retirer du client",  
799 - "assign-edges-text": "Attribuer {count, plural, 1 {1 bordure} other {# bordures}} au client",  
800 - "unassign-edge-title": "Êtes-vous sûr de vouloir annuler l'affection du dispositif {{edgeName}}",  
801 - "unassign-edge-text": "Après la confirmation, le dispositif ne sera pas attribué et ne sera pas accessible au client",  
802 - "make-public": "Make edge public",  
803 - "make-public-edge-title": "Are you sure you want to make the edge '{{edgeName}}' public?",  
804 - "make-public-edge-text": "After the confirmation the edge and all its data will be made public and accessible by others.",  
805 - "make-private": "Rendre public Edge",  
806 - "public": "Public",  
807 - "make-private-edge-title": "Are you sure you want to make the edge '{{edgeName}}' private?",  
808 - "make-private-edge-text": "Après la confirmation, la bordure et toutes ses données seront rendues privées et ne seront pas accessibles par d'autres",  
809 - "import": "Importer bordure",  
810 - "label": "Etiquette",  
811 - "assign-new-edge": "Attribuer un nouvel bordure",  
812 - "manage-edge-dashboards": "Gérer les tableaux de bord",  
813 - "unassign-from-edge": "Retirer de la bordure",  
814 - "dashboards": "Tableau de bord de la bordure",  
815 - "manage-edge-rulechains": "Gérer les chaînes de règles",  
816 - "rulechains": "Chaînes de règles de la bordure",  
817 - "rulechain": "Chaîne de règles de la bordure",  
818 - "edge-key": "Clé de la bordure",  
819 - "copy-edge-key": "Copier clé de la bordure",  
820 - "edge-key-copied-message": "Clé de la bordure a été copié dans le presse-papier",  
821 - "edge-secret": "Secret de la bordure",  
822 - "copy-edge-secret": "Copier secret de la bordure",  
823 - "edge-secret-copied-message": "Secret de la bordure a été copié dans le presse-papier",  
824 - "manage-edge-assets": "Gérer les actifs de la bordure",  
825 - "manage-edge-devices": "Gérer les dispositifs de la bordure",  
826 - "manage-edge-entity-views": "Vues de l'entité vues de l'entité",  
827 - "assets": "Actifs de la bordure",  
828 - "devices": "Dispositifs de la bordure",  
829 - "entity-views": "Vues de l'entité bordure",  
830 - "set-root-rule-chain-text": "Veuillez sélectionner la chaîne de règles racine pour les bordure(s)",  
831 - "set-root-rule-chain-to-edges": "Définir la chaîne de règles racine pour bordure(s)",  
832 - "set-root-rule-chain-to-edges-text": "Définir la chaîne de règles racine pour {count, plural, 1 {1 bordure} other {# bordures} }"  
833 - },  
834 "entity": { 718 "entity": {
835 "add-alias": "Ajouter un alias d'entité", 719 "add-alias": "Ajouter un alias d'entité",
836 "alarm-name-starts-with": "Les actifs dont le nom commence par '{{prefix}}'", 720 "alarm-name-starts-with": "Les actifs dont le nom commence par '{{prefix}}'",
@@ -891,10 +775,6 @@ @@ -891,10 +775,6 @@
891 "rule-name-starts-with": "Régles dont les noms commencent par '{{prefix}}'", 775 "rule-name-starts-with": "Régles dont les noms commencent par '{{prefix}}'",
892 "rulechain-name-starts-with": "Chaînes de régles dont les noms commencent par '{{prefix}}'", 776 "rulechain-name-starts-with": "Chaînes de régles dont les noms commencent par '{{prefix}}'",
893 "rulenode-name-starts-with": "Les noeuds de régles dont le nom commence par '{{prefix}}'", 777 "rulenode-name-starts-with": "Les noeuds de régles dont le nom commence par '{{prefix}}'",
894 - "type-edge": "Bordure",  
895 - "type-edges": "Bordures",  
896 - "list-of-edges": "{ count, plural, 1 {Une bordure} other {List of # bordures} }",  
897 - "edge-name-starts-with": "Bordures dont les noms commencent par '{{prefix}}'",  
898 "search": "Recherche d'entités", 778 "search": "Recherche d'entités",
899 "select-entities": "Sélectionner des entités", 779 "select-entities": "Sélectionner des entités",
900 "selected-entities": "{count, plural, 1 {1 entité} other {# entités} } sélectionnées", 780 "selected-entities": "{count, plural, 1 {1 entité} other {# entités} } sélectionnées",
@@ -1005,17 +885,6 @@ @@ -1005,17 +885,6 @@
1005 "make-public": "Rendre la vue d'entité publique", 885 "make-public": "Rendre la vue d'entité publique",
1006 "make-public-entity-view-text": "Après la confirmation, la vue de l'entité et toutes ses données seront rendues publiques et accessibles à d'autres", 886 "make-public-entity-view-text": "Après la confirmation, la vue de l'entité et toutes ses données seront rendues publiques et accessibles à d'autres",
1007 "make-public-entity-view-title": "Voulez-vous vraiment que la vue de l'entité '{{entityViewName}}' soit publique?", 887 "make-public-entity-view-title": "Voulez-vous vraiment que la vue de l'entité '{{entityViewName}}' soit publique?",
1008 - "assign-entity-view-to-edge": "Attribuer a la bordure",  
1009 - "assign-entity-view-to-edge-text":"Veuillez sélectionner la bordure auquel attribuer la ou les vues d'entité.",  
1010 - "unassign-from-edge": "Retirer de la bordure",  
1011 - "assign-to-edge": "Attribuer a la bordure",  
1012 - "assign-to-edge-text": "Veuillez sélectionner la bordure pour attribuer le ou les actifs",  
1013 - "unassign-entity-view-from-edge-title": "Voulez-vous vraiment annuler l'attribution de la vue d'entité '{{entityViewName}}'?",  
1014 - "unassign-entity-view-from-edge-text": "Après la confirmation, la vue de l'entité sera non attribuée et ne sera pas accessible par la bordure.",  
1015 - "unassign-entity-views-from-edge-action-title": "Annuler l'attribution { count, plural, 1 {1 entityView} other {# entityViews} } de la bordure",  
1016 - "unassign-entity-view-from-edge": "Annuler l'attribution des vues d'entité",  
1017 - "unassign-entity-views-from-edge-title": "Êtes-vous sûr de vouloir annuler l'attribution { count, plural, 1 {1 entityView} other {# entityViews} }?",  
1018 - "unassign-entity-views-from-edge-text": "Après la confirmation, toutes les vues des entités sélectionnées seront non attribuées et ne seront pas accessibles par la bordure.",  
1019 "management": "Gestion de vue d'entité", 888 "management": "Gestion de vue d'entité",
1020 "name": "Nom", 889 "name": "Nom",
1021 "name-required": "Un nom est requis.", 890 "name-required": "Un nom est requis.",
@@ -1430,45 +1299,10 @@ @@ -1430,45 +1299,10 @@
1430 "rulechain-required": "Chaîne de règles requise", 1299 "rulechain-required": "Chaîne de règles requise",
1431 "rulechains": "Chaînes de règles", 1300 "rulechains": "Chaînes de règles",
1432 "select-rulechain": "Sélectionner la chaîne de règles", 1301 "select-rulechain": "Sélectionner la chaîne de règles",
1433 - "core-rulechains": "Chaînes de règles fondamentales",  
1434 - "edge-rulechains": "Chaînes de règles de la bordure",  
1435 "set-root": "Rend la chaîne de règles racine (root) ", 1302 "set-root": "Rend la chaîne de règles racine (root) ",
1436 "set-root-rulechain-text": "Après la confirmation, la chaîne de règles deviendra racine (root) et gérera tous les messages de transport entrants.", 1303 "set-root-rulechain-text": "Après la confirmation, la chaîne de règles deviendra racine (root) et gérera tous les messages de transport entrants.",
1437 "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de règles '{{ruleChainName}} soit racine (root) ?", 1304 "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de règles '{{ruleChainName}} soit racine (root) ?",
1438 - "system": "Système",  
1439 - "assign-rulechains": "Attribuer aux chaînes de règles",  
1440 - "assign-new-rulechain": "Attribuer une nouvele chaînes de règles",  
1441 - "delete-rulechains": "Supprimer une chaînes de règles",  
1442 - "default": "Défaut",  
1443 - "unassign-rulechain": "Retirer chaîne de règles",  
1444 - "unassign-rulechains": "Retirer chaînes de règles",  
1445 - "unassign-rulechain-title": "AÊtes-vous sûr de vouloir retirer l'attribution de chaînes de règles '{{ruleChainTitle}}'?",  
1446 - "unassign-rulechains-title": "Êtes-vous sûr de vouloir retirer l'attribution de {count, plural, 1 {1 chaîne de règles} other {# chaînes de règles}}?",  
1447 - "manage-assigned-edges": "Gérer les bordures affectés",  
1448 - "unassign-rulechain-from-edge-text": "Après la confirmation, l'actif sera non attribué et ne sera pas accessible a la bordure.",  
1449 - "assigned-edges": "Bordures affectés",  
1450 - "unassign-from-edge": "Retirer de la bordure",  
1451 - "unassign-rulechains-from-edge-action-title": "Retirer {count, plural, 1 {1 chaîne de règles} other {# chaînes de règles}} de la bordure",  
1452 - "unassign-rulechains-from-edge-text": "Après la confirmation, tous les chaînes de règles sélectionnés ne seront pas attribués et ne seront pas accessibles a la bordure.",  
1453 - "assign-rulechains-to-edge-text": "Attribuer {count, plural, 1 {1 chaîne de règles} other {# chaînes de règles}} aux bordures",  
1454 - "assign-rulechain-to-edge": "Attribuer les chaînes de règles a la bordure",  
1455 - "assign-rulechain-to-edge-text": "Veuillez sélectionner la bordure pour attribuer le ou les chaînes de règles",  
1456 - "unassign-rulechains-from-edge-action-text": "Annuler l'affectation {count, plural, 1 {1 chaîne de règles} other {# chaînes de règles}} des bordures",  
1457 - "assign-to-edges": "Attribuer des tableaux de bord a la bordures",  
1458 - "assign-to-edges-text": "Please select the edges to assign the rulechain(s)",  
1459 - "unassign-from-edges": "Retirer de la bordure",  
1460 - "unassign-from-edges-text": "Veuillez sélectionner les bordures à annuler l'affectation du ou des chaînes de règles",  
1461 - "assigned-to-edges": "Attribué chaînes de règles",  
1462 - "set-default-root-edge": "Définir la racine par défaut de la chaîne de règles",  
1463 - "set-default-root-edge-rulechain-title": "AVoulez-vous vraiment créer de chaînes de règles par défaut '{{ruleChainName}}'?",  
1464 - "set-default-root-edge-rulechain-text": "Après la confirmation, la chaîne de règles deviendra la racine de la bordure par défaut et gérera tous les messages de transport entrants.",  
1465 - "invalid-rulechain-type-error": "Impossible d'importer la chaîne de règles: type de chaîne de règles non valide. Le type attendu est {{attenduRuleChainType}}.",  
1466 - "set-default-edge": "Définir la chaîne de règles de la bordure par défaut",  
1467 - "set-default-edge-title": "Voulez-vous vraiment définir la chaîne de règles de la bordure '{{ruleChainName}}' par défaut?",  
1468 - "set-default-edge-text": "Après la confirmation, la chaîne de règles d'arête sera ajoutée à la liste par défaut et affectée aux arêtes nouvellement créées.",  
1469 - "remove-default-edge": "Supprimer la chaîne de règles de la bordure des valeurs par défaut",  
1470 - "remove-default-edge-title": "Voulez-vous vraiment supprimer la chaîne de règles de la bordure '{{ruleChainName}}' de la liste par défaut",  
1471 - "remove-default-edge-text": "Après la confirmation, la chaîne de règles d'arête ne sera pas affectée aux arêtes nouvellement créées." 1305 + "system": "Système"
1472 }, 1306 },
1473 "rulenode": { 1307 "rulenode": {
1474 "add": "Ajouter un noeud de règle", 1308 "add": "Ajouter un noeud de règle",