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 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 53 }
54 54 }
55 55
56   - public getComponentDescriptorsByTypes(componentTypes: Array<ComponentType>,
  56 + public getComponentDescriptorsByTypes(componentTypes: Array<ComponentType>, type: string,
57 57 config?: RequestConfig): Observable<Array<ComponentDescriptor>> {
58 58 let result: ComponentDescriptor[] = [];
59 59 for (let i = componentTypes.length - 1; i >= 0; i--) {
... ... @@ -67,7 +67,7 @@ export class ComponentDescriptorService {
67 67 if (!componentTypes.length) {
68 68 return of(result);
69 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 71 defaultHttpOptionsFromConfig(config)).pipe(
72 72 map((componentDescriptors) => {
73 73 componentDescriptors.forEach((componentDescriptor) => {
... ...
... ... @@ -157,4 +157,19 @@ export class DashboardService {
157 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 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 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 57 import { Device, DeviceCredentialsType, DeviceSearchQuery } from '@shared/models/device.models';
58 58 import { EntityViewSearchQuery } from '@shared/models/entity-view.models';
59 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 64 @Injectable({
62 65 providedIn: 'root'
... ... @@ -67,6 +70,7 @@ export class EntityService {
67 70 private http: HttpClient,
68 71 private store: Store<AppState>,
69 72 private deviceService: DeviceService,
  73 + private edgeService: EdgeService,
70 74 private assetService: AssetService,
71 75 private entityViewService: EntityViewService,
72 76 private tenantService: TenantService,
... ... @@ -90,6 +94,9 @@ export class EntityService {
90 94 case EntityType.ASSET:
91 95 observable = this.assetService.getAsset(entityId, config);
92 96 break;
  97 + case EntityType.EDGE:
  98 + observable = this.edgeService.getEdge(entityId, config);
  99 + break;
93 100 case EntityType.ENTITY_VIEW:
94 101 observable = this.entityViewService.getEntityView(entityId, config);
95 102 break;
... ... @@ -157,6 +164,9 @@ export class EntityService {
157 164 case EntityType.ASSET:
158 165 observable = this.assetService.getAssets(entityIds, config);
159 166 break;
  167 + case EntityType.EDGE:
  168 + observable = this.edgeService.getEdges(entityIds, config);
  169 + break;
160 170 case EntityType.ENTITY_VIEW:
161 171 observable = this.getEntitiesByIdsObservable(
162 172 (id) => this.entityViewService.getEntityView(id, config),
... ... @@ -265,6 +275,14 @@ export class EntityService {
265 275 entitiesObservable = this.assetService.getTenantAssetInfos(pageLink, subType, config);
266 276 }
267 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 286 case EntityType.ENTITY_VIEW:
269 287 pageLink.sortOrder.property = 'name';
270 288 if (authUser.authority === Authority.CUSTOMER_USER) {
... ... @@ -292,7 +310,12 @@ export class EntityService {
292 310 break;
293 311 case EntityType.RULE_CHAIN:
294 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 319 break;
297 320 case EntityType.DASHBOARD:
298 321 pageLink.sortOrder.property = 'title';
... ... @@ -390,6 +413,8 @@ export class EntityService {
390 413 return entityTypes.indexOf(EntityType.ASSET) > -1 ? true : false;
391 414 case AliasFilterType.deviceType:
392 415 return entityTypes.indexOf(EntityType.DEVICE) > -1 ? true : false;
  416 + case AliasFilterType.edgeType:
  417 + return entityTypes.indexOf(EntityType.EDGE) > -1 ? true : false;
393 418 case AliasFilterType.entityViewType:
394 419 return entityTypes.indexOf(EntityType.ENTITY_VIEW) > -1 ? true : false;
395 420 case AliasFilterType.relationsQuery:
... ... @@ -416,6 +441,8 @@ export class EntityService {
416 441 return entityTypes.indexOf(EntityType.ASSET) > -1 ? true : false;
417 442 case AliasFilterType.deviceSearchQuery:
418 443 return entityTypes.indexOf(EntityType.DEVICE) > -1 ? true : false;
  444 + case AliasFilterType.edgeSearchQuery:
  445 + return entityTypes.indexOf(EntityType.EDGE) > -1 ? true : false;
419 446 case AliasFilterType.entityViewSearchQuery:
420 447 return entityTypes.indexOf(EntityType.ENTITY_VIEW) > -1 ? true : false;
421 448 }
... ... @@ -449,6 +476,8 @@ export class EntityService {
449 476 return entityType === EntityType.ASSET;
450 477 case AliasFilterType.deviceType:
451 478 return entityType === EntityType.DEVICE;
  479 + case AliasFilterType.edgeType:
  480 + return entityType === EntityType.EDGE;
452 481 case AliasFilterType.entityViewType:
453 482 return entityType === EntityType.ENTITY_VIEW;
454 483 case AliasFilterType.relationsQuery:
... ... @@ -457,6 +486,8 @@ export class EntityService {
457 486 return entityType === EntityType.ASSET;
458 487 case AliasFilterType.deviceSearchQuery:
459 488 return entityType === EntityType.DEVICE;
  489 + case AliasFilterType.edgeSearchQuery:
  490 + return entityType === EntityType.EDGE;
460 491 case AliasFilterType.entityViewSearchQuery:
461 492 return entityType === EntityType.ENTITY_VIEW;
462 493 }
... ... @@ -474,6 +505,7 @@ export class EntityService {
474 505 case Authority.TENANT_ADMIN:
475 506 entityTypes.push(EntityType.DEVICE);
476 507 entityTypes.push(EntityType.ASSET);
  508 + entityTypes.push(EntityType.EDGE);
477 509 entityTypes.push(EntityType.ENTITY_VIEW);
478 510 entityTypes.push(EntityType.TENANT);
479 511 entityTypes.push(EntityType.CUSTOMER);
... ... @@ -486,6 +518,7 @@ export class EntityService {
486 518 case Authority.CUSTOMER_USER:
487 519 entityTypes.push(EntityType.DEVICE);
488 520 entityTypes.push(EntityType.ASSET);
  521 + entityTypes.push(EntityType.EDGE);
489 522 entityTypes.push(EntityType.ENTITY_VIEW);
490 523 entityTypes.push(EntityType.CUSTOMER);
491 524 entityTypes.push(EntityType.DASHBOARD);
... ... @@ -531,6 +564,7 @@ export class EntityService {
531 564 entityFieldKeys.push(entityFields.type.keyName);
532 565 break;
533 566 case EntityType.DEVICE:
  567 + case EntityType.EDGE:
534 568 case EntityType.ASSET:
535 569 entityFieldKeys.push(entityFields.name.keyName);
536 570 entityFieldKeys.push(entityFields.type.keyName);
... ... @@ -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 754 case AliasFilterType.entityViewType:
708 755 return this.getEntitiesByNameFilter(EntityType.ENTITY_VIEW, filter.entityViewNameFilter, maxItems,
709 756 filter.entityViewType, {ignoreLoading: true, ignoreErrors: true}).pipe(
... ... @@ -763,6 +810,7 @@ export class EntityService {
763 810 }
764 811 case AliasFilterType.assetSearchQuery:
765 812 case AliasFilterType.deviceSearchQuery:
  813 + case AliasFilterType.edgeSearchQuery:
766 814 case AliasFilterType.entityViewSearchQuery:
767 815 result.stateEntity = filter.rootStateEntity;
768 816 if (result.stateEntity && stateEntityId) {
... ... @@ -793,6 +841,10 @@ export class EntityService {
793 841 const deviceSearchQuery = searchQuery as DeviceSearchQuery;
794 842 deviceSearchQuery.deviceTypes = filter.deviceTypes;
795 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 848 } else if (filter.type === AliasFilterType.entityViewSearchQuery) {
797 849 const entityViewSearchQuery = searchQuery as EntityViewSearchQuery;
798 850 entityViewSearchQuery.entityViewTypes = filter.entityViewTypes;
... ...
... ... @@ -24,6 +24,7 @@ export * from './customer.service';
24 24 export * from './dashboard.service';
25 25 export * from './device.service';
26 26 export * from './entity.service';
  27 +export * from './edge.service';
27 28 export * from './entity-relation.service';
28 29 export * from './entity-view.service';
29 30 export * from './event.service';
... ...
... ... @@ -25,6 +25,7 @@ import {
25 25 RuleChain,
26 26 RuleChainConnectionInfo,
27 27 RuleChainMetaData,
  28 + ruleChainType,
28 29 ruleChainNodeComponent,
29 30 ruleNodeTypeComponentTypes,
30 31 unknownNodeComponent
... ... @@ -59,8 +60,8 @@ export class RuleChainService {
59 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 65 defaultHttpOptionsFromConfig(config));
65 66 }
66 67
... ... @@ -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 115 Observable<Array<RuleNodeComponentDescriptor>> {
115 116 if (this.ruleNodeComponents) {
116 117 return of(this.ruleNodeComponents);
117 118 } else {
118   - return this.loadRuleNodeComponents(config).pipe(
  119 + return this.loadRuleNodeComponents(type, config).pipe(
119 120 mergeMap((components) => {
120 121 return this.resolveRuleNodeComponentsUiResources(components, ruleNodeConfigResourcesModulesMap).pipe(
121 122 map((ruleNodeComponents) => {
... ... @@ -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 204 map((components) => {
204 205 const ruleNodeComponents: RuleNodeComponentDescriptor[] = [];
205 206 components.forEach((component) => {
... ... @@ -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 180 },
181 181 {
182 182 name: 'rulechain.rulechains',
183   - type: 'link',
  183 + type: 'toggle',
184 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 203 name: 'customer.customers',
... ... @@ -209,6 +224,12 @@ export class MenuService {
209 224 icon: 'view_quilt'
210 225 },
211 226 {
  227 + name: 'edge.edges',
  228 + type: 'link',
  229 + path: '/edges',
  230 + icon: 'router'
  231 + },
  232 + {
212 233 name: 'widget.widget-library',
213 234 type: 'link',
214 235 path: '/widgets-bundles',
... ... @@ -240,6 +261,11 @@ export class MenuService {
240 261 name: 'rulechain.rulechains',
241 262 icon: 'settings_ethernet',
242 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 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 323 name: 'dashboard.management',
288 324 places: [
289 325 {
... ...
... ... @@ -28,6 +28,7 @@ import { EntityViewService } from '@core/http/entity-view.service';
28 28 import { DashboardService } from '@core/http/dashboard.service';
29 29 import { DialogComponent } from '@shared/components/dialog.component';
30 30 import { Router } from '@angular/router';
  31 +import { EdgeService } from "@core/http/edge.service";
31 32
32 33 export interface AddEntitiesToCustomerDialogData {
33 34 customerId: string;
... ... @@ -57,6 +58,7 @@ export class AddEntitiesToCustomerDialogComponent extends
57 58 @Inject(MAT_DIALOG_DATA) public data: AddEntitiesToCustomerDialogData,
58 59 private deviceService: DeviceService,
59 60 private assetService: AssetService,
  61 + private edgeService: EdgeService,
60 62 private entityViewService: EntityViewService,
61 63 private dashboardService: DashboardService,
62 64 @SkipSelf() private errorStateMatcher: ErrorStateMatcher,
... ... @@ -79,6 +81,10 @@ export class AddEntitiesToCustomerDialogComponent extends
79 81 this.assignToCustomerTitle = 'asset.assign-asset-to-customer';
80 82 this.assignToCustomerText = 'asset.assign-asset-to-customer-text';
81 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 88 case EntityType.ENTITY_VIEW:
83 89 this.assignToCustomerTitle = 'entity-view.assign-entity-view-to-customer';
84 90 this.assignToCustomerText = 'entity-view.assign-entity-view-to-customer-text';
... ... @@ -122,6 +128,8 @@ export class AddEntitiesToCustomerDialogComponent extends
122 128 return this.deviceService.assignDeviceToCustomer(customerId, entityId);
123 129 case EntityType.ASSET:
124 130 return this.assetService.assignAssetToCustomer(customerId, entityId);
  131 + case EntityType.EDGE:
  132 + return this.edgeService.assignEdgeToCustomer(customerId, entityId);
125 133 case EntityType.ENTITY_VIEW:
126 134 return this.entityViewService.assignEntityViewToCustomer(customerId, entityId);
127 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 20 import { AssignToCustomerDialogComponent } from '@modules/home/dialogs/assign-to-customer-dialog.component';
21 21 import { AddEntitiesToCustomerDialogComponent } from '@modules/home/dialogs/add-entities-to-customer-dialog.component';
22 22 import { HomeDialogsService } from './home-dialogs.service';
  23 +import { AddEntitiesToEdgeDialogComponent } from "@home/dialogs/add-entities-to-edge-dialog.component";
23 24
24 25 @NgModule({
25 26 declarations:
26 27 [
27 28 AssignToCustomerDialogComponent,
28   - AddEntitiesToCustomerDialogComponent
  29 + AddEntitiesToCustomerDialogComponent,
  30 + AddEntitiesToEdgeDialogComponent
29 31 ],
30 32 imports: [
31 33 CommonModule,
... ... @@ -33,7 +35,8 @@ import { HomeDialogsService } from './home-dialogs.service';
33 35 ],
34 36 exports: [
35 37 AssignToCustomerDialogComponent,
36   - AddEntitiesToCustomerDialogComponent
  38 + AddEntitiesToCustomerDialogComponent,
  39 + AddEntitiesToEdgeDialogComponent
37 40 ],
38 41 providers: [
39 42 HomeDialogsService
... ...
... ... @@ -58,6 +58,11 @@ import { AssetId } from '@app/shared/models/id/asset-id';
58 58 import { AssetTabsComponent } from '@home/pages/asset/asset-tabs.component';
59 59 import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
60 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 67 @Injectable()
63 68 export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<AssetInfo>> {
... ... @@ -65,11 +70,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
65 70 private readonly config: EntityTableConfig<AssetInfo> = new EntityTableConfig<AssetInfo>();
66 71
67 72 private customerId: string;
  73 + private edgeId: string;
68 74
69 75 constructor(private store: Store<AppState>,
70 76 private broadcast: BroadcastService,
71 77 private assetService: AssetService,
72 78 private customerService: CustomerService,
  79 + private edgeService: EdgeService,
73 80 private dialogService: DialogService,
74 81 private homeDialogs: HomeDialogsService,
75 82 private translate: TranslateService,
... ... @@ -111,6 +118,7 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
111 118 assetType: ''
112 119 };
113 120 this.customerId = routeParams.customerId;
  121 + this.edgeId = routeParams.edgeId;
114 122 return this.store.pipe(select(selectAuthUser), take(1)).pipe(
115 123 tap((authUser) => {
116 124 if (authUser.authority === Authority.CUSTOMER_USER) {
... ... @@ -128,7 +136,13 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
128 136 } else {
129 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 146 this.config.tableTitle = this.translate.instant('asset.assets');
133 147 }
134 148 this.config.columns = this.configureColumns(this.config.componentsData.assetScope);
... ... @@ -168,6 +182,10 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
168 182 this.config.entitiesFetchFunction = pageLink =>
169 183 this.assetService.getTenantAssetInfos(pageLink, this.config.componentsData.assetType);
170 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 189 } else {
172 190 this.config.entitiesFetchFunction = pageLink =>
173 191 this.assetService.getCustomerAssetInfos(this.customerId, pageLink, this.config.componentsData.assetType);
... ... @@ -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 252 return actions;
225 253 }
226 254
... ... @@ -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 277 if (assetScope === 'customer') {
240 278 actions.push(
241 279 {
... ... @@ -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 328 return actions;
281 329 }
282 330
... ... @@ -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 380 makePublic($event: Event, asset: Asset) {
313 381 if ($event) {
314 382 $event.stopPropagation();
... ... @@ -426,4 +494,54 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
426 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 109 }
110 110
111 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 27 import { DatePipe } from '@angular/common';
28 28 import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
29 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 31 import { RuleChainService } from '@core/http/rule-chain.service';
32 32 import { RuleChainComponent } from '@modules/home/pages/rulechain/rulechain.component';
33 33 import { DialogService } from '@core/services/dialog.service';
... ... @@ -105,7 +105,7 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
105 105 this.config.deleteEntitiesTitle = count => this.translate.instant('rulechain.delete-rulechains-title', {count});
106 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 109 this.config.loadEntity = id => this.ruleChainService.getRuleChain(id.id);
110 110 this.config.saveEntity = ruleChain => this.ruleChainService.saveRuleChain(ruleChain);
111 111 this.config.deleteEntity = id => this.ruleChainService.deleteRuleChain(id.id);
... ...
... ... @@ -153,6 +153,11 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit
153 153 this.noEntitiesMatchingText = 'device.no-devices-matching';
154 154 this.entityRequiredText = 'device.device-required';
155 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 161 case EntityType.ENTITY_VIEW:
157 162 this.entityText = 'entity-view.entity-view';
158 163 this.noEntitiesMatchingText = 'entity-view.no-entity-views-matching';
... ...
... ... @@ -27,6 +27,7 @@ import { BroadcastService } from '@app/core/services/broadcast.service';
27 27 import { coerceBooleanProperty } from '@angular/cdk/coercion';
28 28 import { AssetService } from '@core/http/asset.service';
29 29 import { EntityViewService } from '@core/http/entity-view.service';
  30 +import { EdgeService } from "@core/http/edge.service";
30 31
31 32 @Component({
32 33 selector: 'tb-entity-subtype-autocomplete',
... ... @@ -82,6 +83,7 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
82 83 public translate: TranslateService,
83 84 private deviceService: DeviceService,
84 85 private assetService: AssetService,
  86 + private edgeService: EdgeService,
85 87 private entityViewService: EntityViewService,
86 88 private fb: FormBuilder) {
87 89 this.subTypeFormGroup = this.fb.group({
... ... @@ -115,6 +117,14 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
115 117 this.subTypes = null;
116 118 });
117 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 128 case EntityType.ENTITY_VIEW:
119 129 this.selectEntitySubtypeText = 'entity-view.select-entity-view-type';
120 130 this.entitySubtypeText = 'entity-view.entity-view-type';
... ... @@ -202,6 +212,9 @@ export class EntitySubTypeAutocompleteComponent implements ControlValueAccessor,
202 212 case EntityType.DEVICE:
203 213 subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true});
204 214 break;
  215 + case EntityType.EDGE:
  216 + subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true});
  217 + break;
205 218 case EntityType.ENTITY_VIEW:
206 219 subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
207 220 break;
... ...
... ... @@ -27,6 +27,7 @@ import { MatChipInputEvent, MatChipList } from '@angular/material/chips';
27 27 import { coerceBooleanProperty } from '@angular/cdk/coercion';
28 28 import { AssetService } from '@core/http/asset.service';
29 29 import { DeviceService } from '@core/http/device.service';
  30 +import { EdgeService } from "@core/http/edge.service";
30 31 import { EntityViewService } from '@core/http/entity-view.service';
31 32 import { BroadcastService } from '@core/services/broadcast.service';
32 33 import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
... ... @@ -96,6 +97,7 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
96 97 public translate: TranslateService,
97 98 private assetService: AssetService,
98 99 private deviceService: DeviceService,
  100 + private edgeService: EdgeService,
99 101 private entityViewService: EntityViewService,
100 102 private fb: FormBuilder) {
101 103 this.entitySubtypeListFormGroup = this.fb.group({
... ... @@ -139,6 +141,15 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
139 141 this.entitySubtypes = null;
140 142 });
141 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 153 case EntityType.ENTITY_VIEW:
143 154 this.placeholder = this.required ? this.translate.instant('entity-view.enter-entity-view-type')
144 155 : this.translate.instant('entity-view.any-entity-view');
... ... @@ -260,6 +271,9 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit,
260 271 case EntityType.DEVICE:
261 272 subTypesObservable = this.deviceService.getDeviceTypes({ignoreLoading: true});
262 273 break;
  274 + case EntityType.EDGE:
  275 + subTypesObservable = this.edgeService.getEdgeTypes({ignoreLoading: true});
  276 + break;
263 277 case EntityType.ENTITY_VIEW:
264 278 subTypesObservable = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
265 279 break;
... ...
... ... @@ -25,6 +25,7 @@ import { DeviceService } from '@core/http/device.service';
25 25 import { EntitySubtype, EntityType } from '@app/shared/models/entity-type.models';
26 26 import { BroadcastService } from '@app/core/services/broadcast.service';
27 27 import { AssetService } from '@core/http/asset.service';
  28 +import { EdgeService } from "@core/http/edge.service";
28 29 import { EntityViewService } from '@core/http/entity-view.service';
29 30
30 31 @Component({
... ... @@ -78,6 +79,7 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
78 79 public translate: TranslateService,
79 80 private deviceService: DeviceService,
80 81 private assetService: AssetService,
  82 + private edgeService: EdgeService,
81 83 private entityViewService: EntityViewService,
82 84 private fb: FormBuilder) {
83 85 this.subTypeFormGroup = this.fb.group({
... ... @@ -111,6 +113,14 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
111 113 this.subTypesOptionsSubject.next('');
112 114 });
113 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 124 case EntityType.ENTITY_VIEW:
115 125 this.entitySubtypeTitle = 'entity-view.entity-view-type';
116 126 this.entitySubtypeRequiredText = 'entity-view.entity-view-type-required';
... ... @@ -208,6 +218,9 @@ export class EntitySubTypeSelectComponent implements ControlValueAccessor, OnIni
208 218 case EntityType.DEVICE:
209 219 this.subTypes = this.deviceService.getDeviceTypes({ignoreLoading: true});
210 220 break;
  221 + case EntityType.EDGE:
  222 + this.subTypes = this.edgeService.getEdgeTypes({ignoreLoading: true});
  223 + break;
211 224 case EntityType.ENTITY_VIEW:
212 225 this.subTypes = this.entityViewService.getEntityViewTypes({ignoreLoading: true});
213 226 break;
... ...
... ... @@ -26,10 +26,12 @@ export enum AliasFilterType {
26 26 stateEntity = 'stateEntity',
27 27 assetType = 'assetType',
28 28 deviceType = 'deviceType',
  29 + edgeType = 'edgeType',
29 30 entityViewType = 'entityViewType',
30 31 relationsQuery = 'relationsQuery',
31 32 assetSearchQuery = 'assetSearchQuery',
32 33 deviceSearchQuery = 'deviceSearchQuery',
  34 + edgeSearchQuery = 'edgeSearchQuery',
33 35 entityViewSearchQuery = 'entityViewSearchQuery'
34 36 }
35 37
... ... @@ -41,10 +43,12 @@ export const aliasFilterTypeTranslationMap = new Map<AliasFilterType, string>(
41 43 [ AliasFilterType.stateEntity, 'alias.filter-type-state-entity' ],
42 44 [ AliasFilterType.assetType, 'alias.filter-type-asset-type' ],
43 45 [ AliasFilterType.deviceType, 'alias.filter-type-device-type' ],
  46 + [ AliasFilterType.edgeType, 'alias.filter-type-edge-type' ],
44 47 [ AliasFilterType.entityViewType, 'alias.filter-type-entity-view-type' ],
45 48 [ AliasFilterType.relationsQuery, 'alias.filter-type-relations-query' ],
46 49 [ AliasFilterType.assetSearchQuery, 'alias.filter-type-asset-search-query' ],
47 50 [ AliasFilterType.deviceSearchQuery, 'alias.filter-type-device-search-query' ],
  51 + [ AliasFilterType.edgeSearchQuery, 'alias.filter-type-edge-search-query' ],
48 52 [ AliasFilterType.entityViewSearchQuery, 'alias.filter-type-entity-view-search-query' ]
49 53 ]
50 54 );
... ... @@ -78,6 +82,11 @@ export interface DeviceTypeFilter {
78 82 deviceNameFilter?: string;
79 83 }
80 84
  85 +export interface EdgeTypeFilter {
  86 + edgeType?: string;
  87 + edgeNameFilter?: string;
  88 +}
  89 +
81 90 export interface EntityViewFilter {
82 91 entityViewType?: string;
83 92 entityViewNameFilter?: string;
... ... @@ -113,6 +122,10 @@ export interface DeviceSearchQueryFilter extends EntitySearchQueryFilter {
113 122 deviceTypes?: string[];
114 123 }
115 124
  125 +export interface EdgeSearchQueryFilter extends EntitySearchQueryFilter {
  126 + edgeTypes?: string[];
  127 +}
  128 +
116 129 export interface EntityViewSearchQueryFilter extends EntitySearchQueryFilter {
117 130 entityViewTypes?: string[];
118 131 }
... ... @@ -124,10 +137,12 @@ export type EntityFilters =
124 137 StateEntityFilter &
125 138 AssetTypeFilter &
126 139 DeviceTypeFilter &
  140 + EdgeTypeFilter &
127 141 EntityViewFilter &
128 142 RelationsQueryFilter &
129 143 AssetSearchQueryFilter &
130 144 DeviceSearchQueryFilter &
  145 + EdgeSearchQueryFilter &
131 146 EntityViewSearchQueryFilter;
132 147
133 148 export interface EntityAliasFilter extends EntityFilters {
... ...
... ... @@ -19,10 +19,12 @@ import { AssetId } from './id/asset-id';
19 19 import { TenantId } from '@shared/models/id/tenant-id';
20 20 import { CustomerId } from '@shared/models/id/customer-id';
21 21 import { EntitySearchQuery } from '@shared/models/relation.models';
  22 +import { EdgeId } from "@shared/models/id/edge-id";
22 23
23 24 export interface Asset extends BaseData<AssetId> {
24 25 tenantId?: TenantId;
25 26 customerId?: CustomerId;
  27 + edgeId?: EdgeId; //TODO: deaflynx: "edgeId?" ?
26 28 name: string;
27 29 type: string;
28 30 label: string;
... ...
... ... @@ -49,7 +49,9 @@ export enum ActionType {
49 49 ALARM_CLEAR = 'ALARM_CLEAR',
50 50 LOGIN = 'LOGIN',
51 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 57 export enum ActionStatus {
... ... @@ -79,7 +81,9 @@ export const actionTypeTranslations = new Map<ActionType, string>(
79 81 [ActionType.ALARM_CLEAR, 'audit-log.type-alarm-clear'],
80 82 [ActionType.LOGIN, 'audit-log.type-login'],
81 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 97 customers: helpBaseUrl + '/docs/user-guide/customers',
98 98 users: helpBaseUrl + '/docs/user-guide/ui/users',
99 99 devices: helpBaseUrl + '/docs/user-guide/ui/devices',
  100 + edges: helpBaseUrl + 'docs/user-guide/ui/edges',
100 101 assets: helpBaseUrl + '/docs/user-guide/ui/assets',
101 102 entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views',
102 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 43 ALARM = 'ALARM',
44 44 RULE_CHAIN = 'RULE_CHAIN',
45 45 RULE_NODE = 'RULE_NODE',
  46 + EDGE = 'EDGE',
46 47 ENTITY_VIEW = 'ENTITY_VIEW',
47 48 WIDGETS_BUNDLE = 'WIDGETS_BUNDLE',
48 49 WIDGET_TYPE = 'WIDGET_TYPE'
... ... @@ -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 161 EntityType.ENTITY_VIEW,
147 162 {
148 163 type: 'entity.type-entity-view',
... ... @@ -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 290 EntityType.ENTITY_VIEW,
270 291 {
271 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 29 export * from './customer.model';
30 30 export * from './dashboard.models';
31 31 export * from './device.models';
  32 +export * from './edge.models';
32 33 export * from './entity.models';
33 34 export * from './entity-type.models';
34 35 export * from './entity-view.models';
... ...
... ... @@ -27,6 +27,7 @@ export interface RuleChain extends BaseData<RuleChainId> {
27 27 firstRuleNodeId: RuleNodeId;
28 28 root: boolean;
29 29 debugMode: boolean;
  30 + type: string;
30 31 configuration?: any;
31 32 additionalInfo?: any;
32 33 }
... ... @@ -62,6 +63,11 @@ export interface RuleChainConnectionInfo {
62 63 type: string;
63 64 }
64 65
  66 +export interface RuleChainType {
  67 + core: string;
  68 + edge: string;
  69 +}
  70 +
65 71 export const ruleNodeTypeComponentTypes: ComponentType[] =
66 72 [
67 73 ComponentType.FILTER,
... ... @@ -110,3 +116,8 @@ export const inputNodeComponent: RuleNodeComponentDescriptor = {
110 116 name: 'Input',
111 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 67 "general-settings": "Allgemeine Einstellungen",
68 68 "outgoing-mail": "E-Mail Versand",
69 69 "outgoing-mail-settings": "Konfiguration des Postausgangsservers",
70   - "system-settings": "Systeminstellungen",
  70 + "system-settings": "Systemeinstellungen",
71 71 "test-mail-sent": "Test E-Mail wurde erfolgreich versendet!",
72 72 "base-url": "Basis-URL",
73 73 "base-url-required": "Basis-URL ist erforderlich.",
... ... @@ -183,8 +183,6 @@
183 183 "filter-type-entity-view-type": "Entitätsansichtstyp",
184 184 "filter-type-entity-view-type-description": "Entitätsansichten vom Typ '{{entityView}}'",
185 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 186 "filter-type-relations-query": "Beziehungsabfrage",
189 187 "filter-type-relations-query-description": "{{entities}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}",
190 188 "filter-type-asset-search-query": "Objektabfrage",
... ... @@ -193,8 +191,6 @@
193 191 "filter-type-device-search-query-description": "Geräte vom Typ {{deviceTypes}} mit {{relationType}} Beziehung {{direction}} {{rootEntity}}",
194 192 "filter-type-entity-view-search-query": "Entitätsansichtsabfrage",
195 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 194 "entity-filter": "Entitätsfilter",
199 195 "resolve-multiple": "Als mehrere Entitäten auflösen",
200 196 "filter-type": "Filtertyp",
... ... @@ -273,14 +269,7 @@
273 269 "no-assets-matching": "Es wurden keine zu '{{entity}}' passenden Objekte gefunden.",
274 270 "asset-required": "Objekt ist erforderlich",
275 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 274 "attribute": {
286 275 "attributes": "Eigenschaften",
... ... @@ -328,8 +317,6 @@
328 317 "type-credentials-updated": "Anmeldeinformationen wurden aktualisiert",
329 318 "type-assigned-to-customer": "Kunden Zuordnung",
330 319 "type-unassigned-from-customer": "Kunden Zuordnung aufgehoben",
331   - "type-assigned-to-edge": "Rand Zuordnung",
332   - "type-unassigned-from-edge": "Rand Zuordnung aufgehoben",
333 320 "type-activated": "Aktiviert",
334 321 "type-suspended": "Ausgesetzt",
335 322 "type-credentials-read": "Anmeldeinformationen gelesen",
... ... @@ -394,7 +381,6 @@
394 381 "public-devices": "Öffentliche Geräte",
395 382 "public-assets": "Öffentliche Objekte",
396 383 "public-entity-views": "Öffentliche Entitätsansichten",
397   - "public-edges": "Öffentliche Rand",
398 384 "add": "Kunde hinzufügen",
399 385 "delete": "Kunde löschen",
400 386 "manage-customer-users": "Kundenbenutzer verwalten",
... ... @@ -403,9 +389,7 @@
403 389 "manage-public-devices": "Öffentliche Geräte verwalten",
404 390 "manage-public-dashboards": "Öffentliche Dashboards verwalten",
405 391 "manage-customer-assets": "Kundenobjekte verwalten",
406   - "manage-customer-edges": "Randobjekte verwalten",
407 392 "manage-public-assets": "Öffentliche Objekte verwalten",
408   - "manage-public-edges": "Öffentliche Rand verwalten",
409 393 "add-customer-text": "Neuen Kunden hinzufügen",
410 394 "no-customers-text": "Keine Kunden gefunden",
411 395 "customer-details": "Kundendetails",
... ... @@ -430,7 +414,6 @@
430 414 "customer-required": "Kunde ist erforderlich",
431 415 "select-default-customer": "Wählen Sie den Standardkunden aus.",
432 416 "default-customer": "Standardkunde",
433   - "edges": "Kunden Rand",
434 417 "default-customer-required": "Ein Standardkunde ist erforderlich, um das Dashboard auf Mandantenebene zu testen."
435 418 },
436 419 "datetime": {
... ... @@ -578,21 +561,7 @@
578 561 "show-details": "Details anzeigen",
579 562 "hide-details": "Details ausblenden",
580 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 566 "datakey": {
598 567 "settings": "Einstellungen",
... ... @@ -723,92 +692,11 @@
723 692 "is-gateway": "Ist ein Gateway",
724 693 "public": "Öffentlich",
725 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 697 "dialog": {
740 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 700 "error": {
813 701 "unable-to-connect": "Es konnte keine Verbindung zum Server hergestellt werden! Bitte überprüfen Sie Ihre Internetverbindung.",
814 702 "unhandled-error-code": "Unbehandelter Fehlercode: {{errorCode}}",
... ... @@ -902,10 +790,6 @@
902 790 "type-rulenodes": "Regelknoten",
903 791 "list-of-rulenodes": "{ count, plural, 1 {Ein Regelknoten} other {Liste von # Regelknoten} }",
904 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 793 "type-current-customer": "Aktueller Kunde",
910 794 "search": "Entitäten suchen",
911 795 "selected-entities": "{ count, plural, 1 {Entität} other {# Entitäten} } ausgewählt",
... ... @@ -978,17 +862,6 @@
978 862 "entity-view-types": "Entitätsansichtstypen",
979 863 "name": "Name",
980 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 865 "description": "Beschreibung",
993 866 "events": "Ereignisse",
994 867 "details": "Details",
... ... @@ -1352,8 +1225,6 @@
1352 1225 "rulechain": {
1353 1226 "rulechain": "Regelkette",
1354 1227 "rulechains": "Regelketten",
1355   - "core-rulechains": "Kernregelketten",
1356   - "edge-rulechains": "Randregelketten",
1357 1228 "root": "Wurzel",
1358 1229 "delete": "Regelkette löschen",
1359 1230 "name": "Name",
... ... @@ -1386,40 +1257,7 @@
1386 1257 "no-rulechains-matching": "Es wurden keine passenden Regelketten für '{{entity}}' gefunden.",
1387 1258 "rulechain-required": "Regelkette ist erforderlich",
1388 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 1262 "rulenode": {
1425 1263 "details": "Details",
... ...
... ... @@ -203,8 +203,6 @@
203 203 "filter-type-entity-view-type": "Entity View type",
204 204 "filter-type-entity-view-type-description": "Entity Views of type '{{entityView}}'",
205 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 206 "filter-type-relations-query": "Relations query",
209 207 "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
210 208 "filter-type-asset-search-query": "Asset search query",
... ... @@ -213,8 +211,6 @@
213 211 "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}",
214 212 "filter-type-entity-view-search-query": "Entity view search query",
215 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 214 "entity-filter": "Entity filter",
219 215 "resolve-multiple": "Resolve as multiple entities",
220 216 "filter-type": "Filter type",
... ... @@ -296,20 +292,9 @@
296 292 "name-starts-with": "Asset name starts with",
297 293 "import": "Import assets",
298 294 "asset-file": "Asset file",
299   - "search": "Search assets",
  295 + "search": "Search assets",
300 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 299 "attribute": {
315 300 "attributes": "Attributes",
... ... @@ -359,8 +344,6 @@
359 344 "type-credentials-updated": "Credentials updated",
360 345 "type-assigned-to-customer": "Assigned to Customer",
361 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 347 "type-activated": "Activated",
365 348 "type-suspended": "Suspended",
366 349 "type-credentials-read": "Credentials read",
... ... @@ -425,8 +408,8 @@
425 408 "public-dashboards": "Public Dashboards",
426 409 "public-devices": "Public Devices",
427 410 "public-assets": "Public Assets",
428   - "public-entity-views": "Public Entity Views",
429 411 "public-edges": "Public Edges",
  412 + "public-entity-views": "Public Entity Views",
430 413 "add": "Add Customer",
431 414 "delete": "Delete customer",
432 415 "manage-customer-users": "Manage customer users",
... ... @@ -435,9 +418,7 @@
435 418 "manage-public-devices": "Manage public devices",
436 419 "manage-public-dashboards": "Manage public dashboards",
437 420 "manage-customer-assets": "Manage customer assets",
438   - "manage-customer-edges": "Manage customer edges",
439 421 "manage-public-assets": "Manage public assets",
440   - "manage-public-edges": "Manage public edges",
441 422 "add-customer-text": "Add new customer",
442 423 "no-customers-text": "No customers found",
443 424 "customer-details": "Customer details",
... ... @@ -464,8 +445,7 @@
464 445 "default-customer": "Default customer",
465 446 "default-customer-required": "Default customer is required in order to debug dashboard on Tenant level",
466 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 450 "datetime": {
471 451 "date-from": "Date from",
... ... @@ -618,21 +598,7 @@
618 598 "select-state": "Select target state",
619 599 "state-controller": "State controller",
620 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 603 "datakey": {
638 604 "settings": "Settings",
... ... @@ -771,18 +737,7 @@
771 737 "import": "Import device",
772 738 "device-file": "Device file",
773 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 742 "dialog": {
788 743 "close": "Close dialog"
... ... @@ -792,74 +747,77 @@
792 747 "row": "Row"
793 748 },
794 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 822 "error": {
865 823 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.",
... ... @@ -954,10 +912,6 @@
954 912 "type-rulenodes": "Rule nodes",
955 913 "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }",
956 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 915 "type-current-customer": "Current Customer",
962 916 "type-current-tenant": "Current Tenant",
963 917 "search": "Search entities",
... ... @@ -1086,18 +1040,7 @@
1086 1040 "make-private-entity-view-title": "Are you sure you want to make the entity view '{{entityViewName}}' private?",
1087 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 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 1045 "event": {
1103 1046 "event-type": "Event type",
... ... @@ -1553,10 +1496,9 @@
1553 1496 "no-relations-text": "No relations found"
1554 1497 },
1555 1498 "rulechain": {
  1499 + "edge-rulechains": "Edge Rule chains",
1556 1500 "rulechain": "Rule chain",
1557 1501 "rulechains": "Rule chains",
1558   - "core-rulechains": "Core Rule chains",
1559   - "edge-rulechains": "Edge Rule chains",
1560 1502 "root": "Root",
1561 1503 "delete": "Delete rule chain",
1562 1504 "name": "Name",
... ... @@ -1592,40 +1534,7 @@
1592 1534 "debug-mode": "Debug mode",
1593 1535 "search": "Search rule chains",
1594 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 1539 "rulenode": {
1631 1540 "details": "Details",
... ...
... ... @@ -9,7 +9,7 @@
9 9 "refresh-token-failed": "No se puede actualizar la sesión"
10 10 },
11 11 "action": {
12   - "activate": "Activar",
  12 + "activate": "Activar",
13 13 "suspend": "Suspender",
14 14 "save": "Guardar",
15 15 "saveAs": "Guardar como",
... ... @@ -192,8 +192,6 @@
192 192 "filter-type-entity-view-type": "Tipo de vista de entidad",
193 193 "filter-type-entity-view-type-description": "Vistas de entidad del tipo '{{entityView}}'",
194 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 195 "filter-type-relations-query": "Consulta de relaciones",
198 196 "filter-type-relations-query-description": "{{entities}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}",
199 197 "filter-type-asset-search-query": "Búsqueda de activos",
... ... @@ -202,14 +200,10 @@
202 200 "filter-type-device-search-query-description": "Dispositivos con tipos {{deviceTypes}} que tienen {{relationType}} relación {{direction}} {{rootEntity}}",
203 201 "filter-type-entity-view-search-query": "Consulta de búsqueda de vista de entidad",
204 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 203 "entity-filter": "Filtro por entidad",
208 204 "resolve-multiple": "Tomar como múltiples entidades",
209 205 "filter-type": "Filtro por tipo",
210 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 207 "entity-filter-no-entity-matched": "No se han encontrado entidades con el filtro especificado.",
214 208 "no-entity-filter-specified": "No hay filtro de entidades especificado",
215 209 "root-state-entity": "Usar estado de panel como raíz",
... ... @@ -398,7 +392,6 @@
398 392 "public-devices": "Dispositivos Públicos",
399 393 "public-assets": "Activos Públicos",
400 394 "public-entity-views": "Vistas de Entidad Públicas",
401   - "public-edge": "Bordes públicos",
402 395 "add": "Agregar cliente",
403 396 "delete": "Borrar cliente",
404 397 "manage-customer-users": "Gestionar usuarios del cliente",
... ... @@ -407,8 +400,6 @@
407 400 "manage-public-devices": "Gestionar dispositivos públicos",
408 401 "manage-public-dashboards": "Gestionar paneles públicos",
409 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 403 "manage-public-assets": "Gestionar activos públicos",
413 404 "add-customer-text": "Agregar nuevo cliente",
414 405 "no-customers-text": "No se encontraron clientes",
... ... @@ -427,7 +418,6 @@
427 418 "description": "Descripción",
428 419 "details": "Detalles",
429 420 "events": "Eventos",
430   - "edge": "Bordes del cliente",
431 421 "copyId": "Copiar ID de cliente",
432 422 "idCopiedMessage": "El ID de cliente se ha copiado al portapapeles",
433 423 "select-customer": "Seleccionar Cliente",
... ... @@ -582,21 +572,7 @@
582 572 "show-details": "Mostrar detalles",
583 573 "hide-details": "Ocultar detalles",
584 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 577 "datakey": {
602 578 "settings": "Ajustes",
... ... @@ -732,18 +708,7 @@
732 708 "device-public": "El dispositivo es público",
733 709 "select-device": "Seleccionar dispositivo",
734 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 713 "dialog": {
749 714 "close": "Cerrar diálogo"
... ... @@ -752,76 +717,6 @@
752 717 "column": "Columna",
753 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 720 "error": {
826 721 "unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.",
827 722 "unhandled-error-code": "Código de error no controlado: {{errorCode}}",
... ... @@ -915,10 +810,6 @@
915 810 "type-rulenodes": "Nodos de reglas",
916 811 "list-of-rulenodes": "{ count, plural, 1 {Un nodo de reglas} other {Lista de # nodos de reglas} }",
917 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 813 "type-current-customer": "Cliente Actual",
923 814 "type-current-tenant": "Propietario Actual",
924 815 "search": "Buscar entidades",
... ... @@ -1041,18 +932,7 @@
1041 932 "make-public-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea pública?",
1042 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 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 937 "event": {
1058 938 "event-type": "Tipo de evento",
... ... @@ -1514,8 +1394,6 @@
1514 1394 "rulechain": {
1515 1395 "rulechain": "Cadena de Regla",
1516 1396 "rulechains": "Cadenas de Reglas",
1517   - "core-rulechains": "Cadenas de reglas centrales",
1518   - "edge-rulechains": "Cadenas de reglas de borde",
1519 1397 "root": "Raíz",
1520 1398 "delete": "Borrar cadena de reglas",
1521 1399 "name": "Nombre",
... ... @@ -1548,40 +1426,7 @@
1548 1426 "no-rulechains-matching": "No se encontraron cadenas de reglas que coincidan con '{{entity}}' .",
1549 1427 "rulechain-required": "Cadena de reglas requerida",
1550 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 1431 "rulenode": {
1587 1432 "details": "Detalles",
... ...
... ... @@ -176,7 +176,7 @@
176 176 "entity-filter": "Filtre d'entité",
177 177 "entity-filter-no-entity-matched": "Aucune entité correspondant au filtre spécifié n'a été trouvée.",
178 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 180 "filter-type-asset-search-query-description": "Actifs de types {{assetTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
181 181 "filter-type-asset-type": "type d'actif",
182 182 "filter-type-asset-type-and-name-description": "Actifs de type '{{assetType}}' et dont le nom commence par '{{prefix}}'",
... ... @@ -190,13 +190,9 @@
190 190 "filter-type-entity-name": "Nom d'entité",
191 191 "filter-type-entity-view-search-query": "Requête de recherche vue d'entité",
192 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 193 "filter-type-entity-view-type": "Type de vue d'entité",
196 194 "filter-type-entity-view-type-and-name-description": "Vues d'entité de type '{{entityView}}' et dont le nom commence par '{{prefix}}'",
197 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 196 "filter-type-relations-query": "Interrogation des relations",
201 197 "filter-type-relations-query-description": "{{entities}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
202 198 "filter-type-required": "Le type de filtre est requis.",
... ... @@ -260,17 +256,6 @@
260 256 "name": "Nom",
261 257 "name-required": "Nom est requis.",
262 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 259 "no-asset-types-matching": "Aucun type d'actif correspondant à {{entitySubtype}} n'a été trouvé. ",
275 260 "no-assets-matching": "Aucun actif correspondant à {{entity}} n'a été trouvé. ",
276 261 "no-assets-text": "Aucun actif trouvé",
... ... @@ -339,8 +324,6 @@
339 324 "type-alarm-ack": "Acquitté",
340 325 "type-alarm-clear": "Effacé",
341 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 327 "type-attributes-deleted": "Attributs supprimés",
345 328 "type-attributes-read": "Attributs lus",
346 329 "type-attributes-updated": "Attributs mis à jour",
... ... @@ -424,13 +407,11 @@
424 407 "description": "Description",
425 408 "details": "Détails",
426 409 "devices": "Dispositifs du client",
427   - "edges": "Bordures du client",
428 410 "entity-views": "Vues de l'entité client",
429 411 "events": "Événements",
430 412 "idCopiedMessage": "L'Id du client a été copié dans le presse-papier",
431 413 "manage-assets": "Gérer les actifs",
432 414 "manage-customer-assets": "Gérer les actifs du client",
433   - "manage-customer-edges": "Gérer les bordures du client",
434 415 "manage-customer-dashboards": "Gérer les tableaux de bord du client",
435 416 "manage-customer-devices": "Gérer les dispositifs du client",
436 417 "manage-customer-users": "Gérer les utilisateurs du client",
... ... @@ -439,7 +420,6 @@
439 420 "manage-public-assets": "Gérer les actifs publics",
440 421 "manage-public-dashboards": "Gérer les tableaux de bord publics",
441 422 "manage-public-devices": "Gérer les dispositifs publics",
442   - "manage-public-edges": "Gérer les bordures publics",
443 423 "manage-users": "Gérer les utilisateurs",
444 424 "management": "Gestion des clients",
445 425 "no-customers-matching": "Aucun client correspondant à '{{entity}} n'a été trouvé.",
... ... @@ -448,7 +428,6 @@
448 428 "public-dashboards": "Tableaux de bord publics",
449 429 "public-devices": "Dispositifs publics",
450 430 "public-entity-views": "Vues d'entités publiques",
451   - "public-edges": "Bordures publics",
452 431 "select-customer": "Sélectionner un client",
453 432 "select-default-customer": "Sélectionnez le client par défaut",
454 433 "title": "Titre",
... ... @@ -593,21 +572,7 @@
593 572 "view-dashboards": "Afficher les tableaux de bord",
594 573 "widget-file": "Fichier du Widget",
595 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 577 "datakey": {
613 578 "advanced": "Avancé",
... ... @@ -745,92 +710,11 @@
745 710 "unassign-from-customer": "Retirer du client",
746 711 "use-device-name-filter": "Utiliser le filtre",
747 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 715 "dialog": {
762 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 718 "entity": {
835 719 "add-alias": "Ajouter un alias d'entité",
836 720 "alarm-name-starts-with": "Les actifs dont le nom commence par '{{prefix}}'",
... ... @@ -891,10 +775,6 @@
891 775 "rule-name-starts-with": "Régles dont les noms commencent par '{{prefix}}'",
892 776 "rulechain-name-starts-with": "Chaînes de régles dont les noms commencent par '{{prefix}}'",
893 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 778 "search": "Recherche d'entités",
899 779 "select-entities": "Sélectionner des entités",
900 780 "selected-entities": "{count, plural, 1 {1 entité} other {# entités} } sélectionnées",
... ... @@ -1005,17 +885,6 @@
1005 885 "make-public": "Rendre la vue d'entité publique",
1006 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 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 888 "management": "Gestion de vue d'entité",
1020 889 "name": "Nom",
1021 890 "name-required": "Un nom est requis.",
... ... @@ -1430,45 +1299,10 @@
1430 1299 "rulechain-required": "Chaîne de règles requise",
1431 1300 "rulechains": "Chaînes de règles",
1432 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 1302 "set-root": "Rend la chaîne de règles racine (root) ",
1436 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 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 1307 "rulenode": {
1474 1308 "add": "Ajouter un noeud de règle",
... ...