Browse Source

Merge pull request #76 from deaflynx/develop/3.3-edge

Develop/3.3 edge Show Edge Info for customer scope, get label, fix import edges
pull/3811/head
VoBa 5 years ago
committed by GitHub
parent
commit
ea7411348b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      application/src/main/data/json/system/widget_bundles/edge_widgets.json
  2. 1
      common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java
  3. 4
      ui-ngx/src/app/core/http/edge.service.ts
  4. 185
      ui-ngx/src/app/core/http/entity.service.ts
  5. 4
      ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts
  6. 56
      ui-ngx/src/app/modules/home/components/import-export/import-dialog-csv.component.ts
  7. 10
      ui-ngx/src/app/modules/home/components/import-export/import-export.models.ts
  8. 18
      ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts
  9. 28
      ui-ngx/src/app/modules/home/components/import-export/table-columns-assignment.component.ts
  10. 2
      ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts
  11. 2
      ui-ngx/src/app/modules/home/dialogs/home-dialogs.service.ts
  12. 3
      ui-ngx/src/app/modules/home/pages/customer/customer.component.html
  13. 7
      ui-ngx/src/app/modules/home/pages/customer/customer.component.ts
  14. 37
      ui-ngx/src/app/modules/home/pages/customer/customers-table-config.resolver.ts
  15. 30
      ui-ngx/src/app/modules/home/pages/edge/edge.component.html
  16. 8
      ui-ngx/src/app/modules/home/pages/edge/edge.component.ts
  17. 7
      ui-ngx/src/app/shared/models/entity.models.ts
  18. 94
      ui-ngx/src/assets/locale/locale.constant-de_DE.json
  19. 18
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  20. 92
      ui-ngx/src/assets/locale/locale.constant-es_ES.json
  21. 89
      ui-ngx/src/assets/locale/locale.constant-fr_FR.json

8
application/src/main/data/json/system/widget_bundles/edge_widgets.json

@ -7,7 +7,7 @@
"widgetTypes": [
{
"alias": "edges_overview",
"name": "Edges Quick Overview",
"name": "Edge Quick Overview",
"descriptor": {
"type": "latest",
"sizeX": 7.5,
@ -15,10 +15,10 @@
"resources": [],
"templateHtml": "<tb-edges-overview-widget \n [ctx]=\"ctx\">\n</tb-edges-overview-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n};\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "{}",
"controllerScript": "self.onInit = function() {\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true\n };\n}\n\nself.onDestroy = function() {\n};\n",
"settingsSchema": "{}\n",
"dataKeySettingsSchema": "{}\n",
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Edges Quick Overview\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"widgetStyle\":{},\"actions\":{}}"
"defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"showTitleIcon\":true,\"titleIcon\":\"router\",\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Edge Quick Overview\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"widgetStyle\":{},\"actions\":{}}"
}
}
]

1
common/data/src/main/java/org/thingsboard/server/common/data/edge/Edge.java

@ -62,6 +62,7 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
this.customerId = edge.getCustomerId();
this.rootRuleChainId = edge.getRootRuleChainId();
this.type = edge.getType();
this.label = edge.getLabel();
this.name = edge.getName();
this.routingKey = edge.getRoutingKey();
this.secret = edge.getSecret();

4
ui-ngx/src/app/core/http/edge.service.ts

@ -104,4 +104,8 @@ export class EdgeService {
public findMissingToRelatedRuleChains(edgeId: string, config?: RequestConfig): Observable<string> {
return this.http.get<string>(`/api/edge/missingToRelatedRuleChains/${edgeId}`, defaultHttpOptionsFromConfig(config));
}
public findByName(edgeName: string, config?: RequestConfig): Observable<Edge> {
return this.http.get<Edge>(`/api/tenant/edges?edgeName=${edgeName}`, defaultHttpOptionsFromConfig(config));
}
}

185
ui-ngx/src/app/core/http/entity.service.ts

@ -45,6 +45,7 @@ import { DataKey, Datasource, DatasourceType, KeyInfo } from '@app/shared/models
import { UtilsService } from '@core/services/utils.service';
import { AliasFilterType, EntityAlias, EntityAliasFilter, EntityAliasFilterResult } from '@shared/models/alias.models';
import {
EdgeImportEntityData,
EntitiesKeysByQuery,
entityFields,
EntityInfo,
@ -52,7 +53,7 @@ import {
ImportEntityData
} from '@shared/models/entity.models';
import { EntityRelationService } from '@core/http/entity-relation.service';
import { deepClone, isDefined, isDefinedAndNotNull } from '@core/utils';
import { deepClone, generateSecret, guid, isDefined, isDefinedAndNotNull } from '@core/utils';
import { Asset } from '@shared/models/asset.models';
import { Device, DeviceCredentialsType } from '@shared/models/device.models';
import { AttributeService } from '@core/http/attribute.service';
@ -76,6 +77,7 @@ import {
import { alarmFields } from '@shared/models/alarm.models';
import { EdgeService } from "@core/http/edge.service";
import { RuleChainType } from "@shared/models/rule-chain.models";
import { Edge } from '@shared/models/edge.models';
@Injectable({
providedIn: 'root'
@ -924,6 +926,51 @@ export class EntityService {
public saveEntityParameters(entityType: EntityType, entityData: ImportEntityData, update: boolean,
config?: RequestConfig): Observable<ImportEntitiesResultInfo> {
const saveEntityObservable: Observable<BaseData<EntityId>> = this.getSaveEntityObservable(entityType, entityData, config);
return saveEntityObservable.pipe(
mergeMap((entity) => {
return this.saveEntityData(entity.id, entityData, config).pipe(
map(() => {
return { create: { entity: 1 } } as ImportEntitiesResultInfo;
}),
catchError(err => of({ error: { entity: 1 } } as ImportEntitiesResultInfo))
);
}),
catchError(err => {
if (update) {
let findEntityObservable: Observable<BaseData<EntityId>>;
switch (entityType) {
case EntityType.DEVICE:
findEntityObservable = this.deviceService.findByName(entityData.name, config);
break;
case EntityType.ASSET:
findEntityObservable = this.assetService.findByName(entityData.name, config);
break;
case EntityType.EDGE:
findEntityObservable = this.edgeService.findByName(entityData.name, config);
break;
}
return findEntityObservable.pipe(
mergeMap((entity) => {
const updateEntityTasks: Observable<any>[] = this.getUpdateEntityTasks(entityType, entityData, entity, config);
return forkJoin(updateEntityTasks).pipe(
map(() => {
return { update: { entity: 1 } } as ImportEntitiesResultInfo;
}),
catchError(updateError => of({ error: { entity: 1 } } as ImportEntitiesResultInfo))
);
}),
catchError(findErr => of({ error: { entity: 1 } } as ImportEntitiesResultInfo))
);
} else {
return of({ error: { entity: 1 } } as ImportEntitiesResultInfo);
}
})
);
}
private getSaveEntityObservable(entityType: EntityType, entityData: ImportEntityData,
config?: RequestConfig): Observable<BaseData<EntityId>> {
let saveEntityObservable: Observable<BaseData<EntityId>>;
switch (entityType) {
case EntityType.DEVICE:
@ -954,70 +1001,92 @@ export class EntityService {
};
saveEntityObservable = this.assetService.saveAsset(asset, config);
break;
case EntityType.EDGE:
const edgeEntityData: EdgeImportEntityData = entityData as EdgeImportEntityData;
const edge: Edge = {
name: edgeEntityData.name,
type: edgeEntityData.type,
label: edgeEntityData.label,
additionalInfo: {
description: edgeEntityData.description
},
edgeLicenseKey: edgeEntityData.edgeLicenseKey,
cloudEndpoint: edgeEntityData.cloudEndpoint !== '' ? edgeEntityData.cloudEndpoint : window.location.origin,
routingKey: edgeEntityData.routingKey !== '' ? edgeEntityData.routingKey : guid(),
secret: edgeEntityData.secret !== '' ? edgeEntityData.secret : generateSecret(20)
};
saveEntityObservable = this.edgeService.saveEdge(edge, config);
break;
}
return saveEntityObservable.pipe(
mergeMap((entity) => {
return this.saveEntityData(entity.id, entityData, config).pipe(
map(() => {
return { create: { entity: 1 } } as ImportEntitiesResultInfo;
}),
catchError(err => of({ error: { entity: 1 } } as ImportEntitiesResultInfo))
);
}),
catchError(err => {
if (update) {
let findEntityObservable: Observable<BaseData<EntityId>>;
switch (entityType) {
return saveEntityObservable;
}
private getUpdateEntityTasks(entityType: EntityType, entityData: ImportEntityData | EdgeImportEntityData,
entity: BaseData<EntityId>, config?: RequestConfig): Observable<any>[] {
const tasks: Observable<any>[] = [];
let result;
let additionalInfo;
switch (entityType) {
case EntityType.ASSET:
case EntityType.DEVICE:
result = entity as (Device | Asset);
additionalInfo = result.additionalInfo || {};
if (result.label !== entityData.label ||
result.type !== entityData.type ||
additionalInfo.description !== entityData.description ||
(result.id.entityType === EntityType.DEVICE && (additionalInfo.gateway !== entityData.gateway)) ) {
result.label = entityData.label;
result.type = entityData.type;
result.additionalInfo = additionalInfo;
result.additionalInfo.description = entityData.description;
if (result.id.entityType === EntityType.DEVICE) {
result.additionalInfo.gateway = entityData.gateway;
}
switch (result.id.entityType) {
case EntityType.DEVICE:
findEntityObservable = this.deviceService.findByName(entityData.name, config);
tasks.push(this.deviceService.saveDevice(result, config));
break;
case EntityType.ASSET:
findEntityObservable = this.assetService.findByName(entityData.name, config);
tasks.push(this.assetService.saveAsset(result, config));
break;
}
return findEntityObservable.pipe(
mergeMap((entity) => {
const tasks: Observable<any>[] = [];
const result: Device & Asset = entity as (Device | Asset);
const additionalInfo = result.additionalInfo || {};
if (result.label !== entityData.label ||
result.type !== entityData.type ||
additionalInfo.description !== entityData.description ||
(result.id.entityType === EntityType.DEVICE && (additionalInfo.gateway !== entityData.gateway)) ) {
result.label = entityData.label;
result.type = entityData.type;
result.additionalInfo = additionalInfo;
result.additionalInfo.description = entityData.description;
if (result.id.entityType === EntityType.DEVICE) {
result.additionalInfo.gateway = entityData.gateway;
}
if (result.id.entityType === EntityType.DEVICE && result.deviceProfileId) {
delete result.deviceProfileId;
}
switch (result.id.entityType) {
case EntityType.DEVICE:
tasks.push(this.deviceService.saveDevice(result, config));
break;
case EntityType.ASSET:
tasks.push(this.assetService.saveAsset(result, config));
break;
}
}
tasks.push(this.saveEntityData(entity.id, entityData, config));
return forkJoin(tasks).pipe(
map(() => {
return { update: { entity: 1 } } as ImportEntitiesResultInfo;
}),
catchError(updateError => of({ error: { entity: 1 } } as ImportEntitiesResultInfo))
);
}),
catchError(findErr => of({ error: { entity: 1 } } as ImportEntitiesResultInfo))
);
} else {
return of({ error: { entity: 1 } } as ImportEntitiesResultInfo);
}
})
);
tasks.push(this.saveEntityData(entity.id, entityData, config));
break;
case EntityType.EDGE:
result = entity as Edge;
additionalInfo = result.additionalInfo || {};
const edgeEntityData: EdgeImportEntityData = entityData as EdgeImportEntityData;
if (result.label !== edgeEntityData.label ||
result.type !== edgeEntityData.type ||
(edgeEntityData.cloudEndpoint !== '' && result.cloudEndpoint !== edgeEntityData.cloudEndpoint) ||
(edgeEntityData.edgeLicenseKey !== '' && result.edgeLicenseKey !== edgeEntityData.edgeLicenseKey) ||
(edgeEntityData.routingKey !== '' && result.routingKey !== edgeEntityData.routingKey) ||
(edgeEntityData.secret !== '' && result.secret !== edgeEntityData.secret) ||
additionalInfo.description !== edgeEntityData.description) {
result.label = edgeEntityData.label;
result.type = edgeEntityData.type;
result.additionalInfo = additionalInfo;
result.additionalInfo.description = edgeEntityData.description;
if (edgeEntityData.cloudEndpoint !== '') {
result.cloudEndpoint = edgeEntityData.cloudEndpoint;
}
if (edgeEntityData.edgeLicenseKey !== '') {
result.edgeLicenseKey = edgeEntityData.edgeLicenseKey;
}
if (edgeEntityData.routingKey !== '') {
result.routingKey = edgeEntityData.routingKey;
}
if (edgeEntityData.secret !== '') {
result.secret = edgeEntityData.secret;
}
tasks.push(this.edgeService.saveEdge(result, config));
}
tasks.push(this.saveEntityData(entity.id, edgeEntityData, config));
break;
}
return tasks;
}
public saveEntityData(entityId: EntityId, entityData: ImportEntityData, config?: RequestConfig): Observable<any> {

4
ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts

@ -222,9 +222,9 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig<EdgeEvent, TimePa
updateEdgeEventStatus(createdTime) {
if (this.queueStartTs && createdTime < this.queueStartTs) {
return this.translate.instant('edge.success');
return this.translate.instant('edge.deployed');
} else {
return this.translate.instant('edge.failed');
return this.translate.instant('edge.pending');
}
}

56
ui-ngx/src/app/modules/home/components/import-export/import-dialog-csv.component.ts

@ -32,7 +32,7 @@ import {
CsvToJsonResult,
ImportEntityColumnType
} from '@home/components/import-export/import-export.models';
import { ImportEntitiesResultInfo, ImportEntityData } from '@app/shared/models/entity.models';
import { EdgeImportEntityData, ImportEntitiesResultInfo, ImportEntityData } from '@app/shared/models/entity.models';
import { ImportExportService } from '@home/components/import-export/import-export.service';
export interface ImportDialogCsvData {
@ -186,25 +186,14 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
return columnsParam;
}
private addEntities() {
const importData = this.parseData;
const parameterColumns: CsvColumnParam[] = this.columnTypesFormGroup.get('columnsParam').value;
const entitiesData: ImportEntityData[] = [];
let sentDataLength = 0;
for (let row = 0; row < importData.rows.length; row++) {
const entityData: ImportEntityData = {
name: '',
type: '',
description: '',
gateway: null,
label: '',
accessToken: '',
attributes: {
server: [],
shared: []
},
timeseries: []
};
const entityData: ImportEntityData = this.constructDraftImportEntityData();
const i = row;
for (let j = 0; j < parameterColumns.length; j++) {
switch (parameterColumns[j].type) {
@ -244,6 +233,18 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
case ImportEntityColumnType.description:
entityData.description = importData.rows[i][j];
break;
case ImportEntityColumnType.edgeLicenseKey:
(entityData as EdgeImportEntityData).edgeLicenseKey = importData.rows[i][j];
break;
case ImportEntityColumnType.cloudEndpoint:
(entityData as EdgeImportEntityData).cloudEndpoint = importData.rows[i][j];
break;
case ImportEntityColumnType.routingKey:
(entityData as EdgeImportEntityData).routingKey = importData.rows[i][j];
break;
case ImportEntityColumnType.secret:
(entityData as EdgeImportEntityData).secret = importData.rows[i][j];
break;
}
}
entitiesData.push(entityData);
@ -265,4 +266,31 @@ export class ImportDialogCsvComponent extends DialogComponent<ImportDialogCsvCom
);
}
private constructDraftImportEntityData(): ImportEntityData {
const entityData: ImportEntityData = {
name: '',
type: '',
description: '',
gateway: null,
label: '',
accessToken: '',
attributes: {
server: [],
shared: []
},
timeseries: []
};
if (this.entityType === EntityType.EDGE) {
const edgeEntityData: EdgeImportEntityData = entityData as EdgeImportEntityData;
edgeEntityData.edgeLicenseKey = '';
edgeEntityData.cloudEndpoint = '';
edgeEntityData.routingKey = '';
edgeEntityData.secret = '';
return edgeEntityData;
} else {
return entityData;
}
}
}

10
ui-ngx/src/app/modules/home/components/import-export/import-export.models.ts

@ -49,7 +49,11 @@ export enum ImportEntityColumnType {
entityField = 'ENTITY_FIELD',
accessToken = 'ACCESS_TOKEN',
isGateway = 'IS_GATEWAY',
description = 'DESCRIPTION'
description = 'DESCRIPTION',
edgeLicenseKey = 'EDGE_LICENSE_KEY',
cloudEndpoint = 'CLOUD_ENDPOINT',
routingKey = 'ROUTING_KEY',
secret = 'SECRET'
}
export const importEntityObjectColumns =
@ -68,6 +72,10 @@ export const importEntityColumnTypeTranslations = new Map<ImportEntityColumnType
[ImportEntityColumnType.accessToken, 'import.column-type.access-token'],
[ImportEntityColumnType.isGateway, 'import.column-type.isgateway'],
[ImportEntityColumnType.description, 'import.column-type.description'],
[ImportEntityColumnType.edgeLicenseKey, 'import.column-type.edge-license-key'],
[ImportEntityColumnType.cloudEndpoint, 'import.column-type.cloud-endpoint'],
[ImportEntityColumnType.routingKey, 'import.column-type.routing-key'],
[ImportEntityColumnType.secret, 'import.column-type.secret']
]
);

18
ui-ngx/src/app/modules/home/components/import-export/import-export.service.ts

@ -52,12 +52,7 @@ import { NULL_UUID } from '@shared/models/id/has-uuid';
import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
import { ImportEntitiesResultInfo, ImportEntityData } from '@shared/models/entity.models';
import { RequestConfig } from '@core/http/http-utils';
import {
RuleChain,
RuleChainImport,
RuleChainMetaData,
RuleChainType
} from '@shared/models/rule-chain.models';
import { RuleChain, RuleChainImport, RuleChainMetaData, RuleChainType } from '@shared/models/rule-chain.models';
import { RuleChainService } from '@core/http/rule-chain.service';
import { FiltersInfo } from '@shared/models/query/query.models';
@ -348,8 +343,9 @@ export class ImportExportService {
let statisticalInfo: ImportEntitiesResultInfo = {};
const importEntitiesObservables: Observable<ImportEntitiesResultInfo>[] = [];
for (let i = 0; i < partSize; i++) {
const importEntityPromise =
this.entityService.saveEntityParameters(entityType, entitiesData[i], updateData, config).pipe(
let saveEntityPromise: Observable<ImportEntitiesResultInfo>;
saveEntityPromise = this.entityService.saveEntityParameters(entityType, entitiesData[i], updateData, config);
const importEntityPromise = saveEntityPromise.pipe(
tap((res) => {
if (importEntityCompleted) {
importEntityCompleted();
@ -411,7 +407,7 @@ export class ImportExportService {
throw new Error('Invalid rule chain file');
} else if (ruleChainImport.ruleChain.type !== expectedRuleChainType) {
this.store.dispatch(new ActionNotificationShow(
{message: this.translate.instant('rulechain.invalid-rulechain-type-error', { expectedRuleChainType: expectedRuleChainType }),
{message: this.translate.instant('rulechain.invalid-rulechain-type-error', {expectedRuleChainType}),
type: 'error'}));
throw new Error('Invalid rule chain type');
} else {
@ -603,7 +599,7 @@ export class ImportExportService {
private editMissingAliases(widgets: Array<Widget>, isSingleWidget: boolean,
customTitle: string, missingEntityAliases: EntityAliases): Observable<EntityAliases> {
let allowedEntityTypes: Array<EntityType | AliasEntityType> =
const allowedEntityTypes: Array<EntityType | AliasEntityType> =
this.entityService.prepareAllowedEntityTypesList(null, true);
return this.dialog.open<EntityAliasesDialogComponent, EntityAliasesDialogData,
@ -616,7 +612,7 @@ export class ImportExportService {
customTitle,
isSingleWidget,
disableAdd: true,
allowedEntityTypes: allowedEntityTypes
allowedEntityTypes
}
}).afterClosed().pipe(
map((updatedEntityAliases) => {

28
ui-ngx/src/app/modules/home/components/import-export/table-columns-assignment.component.ts

@ -93,6 +93,14 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
{ value: ImportEntityColumnType.timeseries }
);
break;
case EntityType.EDGE:
this.columnTypes.push(
{ value: ImportEntityColumnType.edgeLicenseKey },
{ value: ImportEntityColumnType.cloudEndpoint },
{ value: ImportEntityColumnType.routingKey },
{ value: ImportEntityColumnType.secret }
);
break;
}
}
@ -118,6 +126,10 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
const isSelectCredentials = this.columns.findIndex((column) => column.type === ImportEntityColumnType.accessToken) > -1;
const isSelectGateway = this.columns.findIndex((column) => column.type === ImportEntityColumnType.isGateway) > -1;
const isSelectDescription = this.columns.findIndex((column) => column.type === ImportEntityColumnType.description) > -1;
const isSelectEdgeLicenseKey = this.columns.findIndex((column) => column.type === ImportEntityColumnType.edgeLicenseKey) > -1;
const isSelectCloudEndpoint = this.columns.findIndex((column) => column.type === ImportEntityColumnType.cloudEndpoint) > -1;
const isSelectRoutingKey = this.columns.findIndex((column) => column.type === ImportEntityColumnType.routingKey) > -1;
const isSelectSecret = this.columns.findIndex((column) => column.type === ImportEntityColumnType.secret) > -1;
const hasInvalidColumn = this.columns.findIndex((column) => !this.columnValid(column)) > -1;
this.valid = isSelectName && isSelectType && !hasInvalidColumn;
@ -135,6 +147,22 @@ export class TableColumnsAssignmentComponent implements OnInit, ControlValueAcce
if (accessTokenColumnType) {
accessTokenColumnType.disabled = isSelectCredentials;
}
const edgeLicenseKeyColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.edgeLicenseKey);
if (edgeLicenseKeyColumnType) {
edgeLicenseKeyColumnType.disabled = isSelectEdgeLicenseKey;
}
const cloudEndpointColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.cloudEndpoint);
if (cloudEndpointColumnType) {
cloudEndpointColumnType.disabled = isSelectCloudEndpoint;
}
const routingKeyColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.routingKey);
if (routingKeyColumnType) {
routingKeyColumnType.disabled = isSelectRoutingKey;
}
const secretColumnType = this.columnTypes.find((columnType) => columnType.value === ImportEntityColumnType.secret);
if (secretColumnType) {
secretColumnType.disabled = isSelectSecret;
}
if (this.propagateChange) {
this.propagateChange(this.columns);
} else {

2
ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts

@ -87,7 +87,7 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni
if (datasource.type === DatasourceType.entity && datasource.entity.id.entityType === EntityType.EDGE) {
var selectedEdge: BaseData<EntityId> = datasource.entity;
this.getCustomerTitle(selectedEdge.id.id);
this.ctx.widgetTitle = selectedEdge.name;
this.ctx.widgetTitle = `${selectedEdge.name} Quick Overview`;
cb(this.loadNodesForEdge(selectedEdge.id.id, selectedEdge));
} else if (datasource.type === DatasourceType.function) {
cb(this.loadNodesForEdge(datasource.entityId, datasource.entity));

2
ui-ngx/src/app/modules/home/dialogs/home-dialogs.service.ts

@ -36,6 +36,8 @@ export class HomeDialogsService {
return this.openImportDialogCSV(entityType, 'device.import', 'device.device-file');
case EntityType.ASSET:
return this.openImportDialogCSV(entityType, 'asset.import', 'asset.asset-file');
case EntityType.EDGE:
return this.openImportDialogCSV(entityType, 'edge.import', 'edge.edge-file');
}
}

3
ui-ngx/src/app/modules/home/pages/customer/customer.component.html

@ -43,7 +43,8 @@
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'manageEdges')"
[fxShow]="!isEdit">
[fxShow]="!isEdit"
*ngIf="edgesSupportEnabled()">
{{'customer.manage-edges' | translate }}
</button>
<button mat-raised-button color="primary"

7
ui-ngx/src/app/modules/home/pages/customer/customer.component.ts

@ -23,6 +23,8 @@ import { ActionNotificationShow } from '@app/core/notification/notification.acti
import { TranslateService } from '@ngx-translate/core';
import { ContactBasedComponent } from '../../components/entity/contact-based.component';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import { getCurrentAuthState } from '@core/auth/auth.selectors';
import { AuthState } from '@core/auth/auth.models';
@Component({
selector: 'tb-customer',
@ -32,6 +34,8 @@ export class CustomerComponent extends ContactBasedComponent<Customer> {
isPublic = false;
authState: AuthState = getCurrentAuthState(this.store);
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@Inject('entity') protected entityValue: Customer,
@ -78,4 +82,7 @@ export class CustomerComponent extends ContactBasedComponent<Customer> {
}));
}
edgesSupportEnabled() {
return this.authState.edgesSupportEnabled;
}
}

37
ui-ngx/src/app/modules/home/pages/customer/customers-table-config.resolver.ts

@ -31,6 +31,9 @@ import { Customer } from '@app/shared/models/customer.model';
import { CustomerService } from '@app/core/http/customer.service';
import { CustomerComponent } from '@modules/home/pages/customer/customer.component';
import { CustomerTabsComponent } from '@home/pages/customer/customer-tabs.component';
import { getCurrentAuthState } from '@core/auth/auth.selectors';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@Injectable()
export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<Customer>> {
@ -40,13 +43,15 @@ export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<C
constructor(private customerService: CustomerService,
private translate: TranslateService,
private datePipe: DatePipe,
private router: Router) {
private router: Router,
private store: Store<AppState>) {
this.config.entityType = EntityType.CUSTOMER;
this.config.entityComponent = CustomerComponent;
this.config.entityTabsComponent = CustomerTabsComponent;
this.config.entityTranslations = entityTypeTranslations.get(EntityType.CUSTOMER);
this.config.entityResources = entityTypeResources.get(EntityType.CUSTOMER);
const authState = getCurrentAuthState(this.store);
this.config.columns.push(
new DateEntityTableColumn<Customer>('createdTime', 'common.created-time', this.datePipe, '150px'),
@ -55,7 +60,6 @@ export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<C
new EntityTableColumn<Customer>('country', 'contact.country', '25%'),
new EntityTableColumn<Customer>('city', 'contact.city', '25%')
);
this.config.cellActionDescriptors.push(
{
name: this.translate.instant('customer.manage-customer-users'),
@ -95,19 +99,22 @@ export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<C
icon: 'dashboard',
isEnabled: (customer) => true,
onAction: ($event, entity) => this.manageCustomerDashboards($event, entity)
},
{
name: this.translate.instant('customer.manage-customer-edges'),
nameFunction: (customer) => {
return customer.additionalInfo && customer.additionalInfo.isPublic
? this.translate.instant('customer.manage-public-edges')
: this.translate.instant('customer.manage-customer-edges');
},
icon: 'router',
isEnabled: (customer) => true,
onAction: ($event, entity) => this.manageCustomerEdges($event, entity)
},
);
});
if (authState.edgesSupportEnabled) {
this.config.cellActionDescriptors.push(
{
name: this.translate.instant('customer.manage-customer-edges'),
nameFunction: (customer) => {
return customer.additionalInfo && customer.additionalInfo.isPublic
? this.translate.instant('customer.manage-public-edges')
: this.translate.instant('customer.manage-customer-edges');
},
icon: 'router',
isEnabled: (customer) => true,
onAction: ($event, entity) => this.manageCustomerEdges($event, entity)
}
);
}
this.config.deleteEntityTitle = customer => this.translate.instant('customer.delete-customer-title', { customerTitle: customer.title });
this.config.deleteEntityContent = () => this.translate.instant('customer.delete-customer-text');

30
ui-ngx/src/app/modules/home/pages/edge/edge.component.html

@ -44,31 +44,31 @@
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'openEdgeAssets')"
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer_user')">
[fxShow]="!isEdit">
{{'edge.manage-edge-assets' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'openEdgeDevices')"
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer_user')">
[fxShow]="!isEdit">
{{'edge.manage-edge-devices' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'openEdgeEntityViews')"
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer_user')">
[fxShow]="!isEdit">
{{'edge.manage-edge-entity-views' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'openEdgeDashboards')"
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer_user')">
[fxShow]="!isEdit">
{{'edge.manage-edge-dashboards' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'openEdgeRuleChains')"
[fxShow]="!isEdit && edgeScope === 'tenant'">
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer')">
{{'edge.manage-edge-rulechains' | translate }}
</button>
</div>
@ -85,7 +85,7 @@
ngxClipboard
(cbOnSuccess)="onEdgeInfoCopied('key')"
[cbContent]="entity?.routingKey"
[fxShow]="!isEdit && edgeScope === 'tenant'">
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer')">
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
<span translate>edge.copy-edge-key</span>
</button>
@ -93,7 +93,7 @@
ngxClipboard
(cbOnSuccess)="onEdgeInfoCopied('secret')"
[cbContent]="entity?.secret"
[fxShow]="!isEdit && edgeScope === 'tenant'">
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer')">
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
<span translate>edge.copy-edge-secret</span>
</button>
@ -101,7 +101,7 @@
ngxClipboard
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'syncEdge')"
[fxShow]="!isEdit && edgeScope === 'tenant'">
[fxShow]="!isEdit && (edgeScope === 'tenant' || edgeScope === 'customer')">
<mat-icon svgIcon="mdi:sync"></mat-icon>
<span translate>edge.sync</span>
</button>
@ -111,12 +111,12 @@
<mat-form-field class="mat-block"
[fxShow]="!isEdit && isAssignedToCustomer(entity)
&& !entity?.customerIsPublic && edgeScope === 'tenant'">
<mat-label translate>edge.assigned-to-customer</mat-label>
<mat-label translate>edge.assignedToCustomer</mat-label>
<input matInput disabled [ngModel]="entity?.customerTitle">
</mat-form-field>
<div class="tb-small" style="padding-bottom: 10px; padding-left: 2px;"
[fxShow]="!isEdit && entity?.customerIsPublic && (edgeScope === 'customer' || edgeScope === 'tenant')">
{{ 'edge.public' | translate }}
[fxShow]="!isEdit && entity?.customerIsPublic && edgeScope === 'tenant'">
{{ 'edge.edge-public' | translate }}
</div>
<form [formGroup]="entityForm">
<fieldset [disabled]="(isLoading$ | async) || !isEdit">
@ -132,7 +132,7 @@
[required]="true"
[entityType]="entityType.EDGE">
</tb-entity-subtype-autocomplete>
<div [fxShow]="edgeScope === 'tenant'">
<div [fxShow]="(edgeScope === 'tenant' || edgeScope === 'customer')">
<div class="tb-hint" [innerHTML]="'edge.edge-license-key-hint' | translate"></div>
<mat-form-field class="mat-block">
<mat-label translate>edge.edge-license-key</mat-label>
@ -142,7 +142,7 @@
</mat-error>
</mat-form-field>
</div>
<div [fxShow]="edgeScope === 'tenant'">
<div [fxShow]="(edgeScope === 'tenant' || edgeScope === 'customer')">
<div translate class="tb-hint">edge.cloud-endpoint-hint</div>
<mat-form-field class="mat-block">
<mat-label translate>edge.cloud-endpoint</mat-label>
@ -153,7 +153,7 @@
</mat-form-field>
</div>
</fieldset>
<div fxLayout="row" [fxShow]="edgeScope === 'tenant'">
<div fxLayout="row" [fxShow]="(edgeScope === 'tenant' || edgeScope === 'customer')">
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>edge.edge-key</mat-label>
<input matInput formControlName="routingKey">
@ -164,7 +164,7 @@
<mat-icon svgIcon="mdi:clipboard-arrow-left"></mat-icon>
</button>
</div>
<div fxLayout="row" [fxShow]="edgeScope === 'tenant'">
<div fxLayout="row" [fxShow]="(edgeScope === 'tenant' || edgeScope === 'customer')">
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>edge.edge-secret</mat-label>
<input matInput formControlName="secret">

8
ui-ngx/src/app/modules/home/pages/edge/edge.component.ts

@ -26,7 +26,6 @@ import { NULL_UUID } from '@shared/models/id/has-uuid';
import { ActionNotificationShow } from '@core/notification/notification.actions';
import { generateSecret, guid } from '@core/utils';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import { WINDOW } from '@core/services/window.service';
@Component({
selector: 'tb-edge',
@ -43,15 +42,14 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
protected translate: TranslateService,
@Inject('entity') protected entityValue: EdgeInfo,
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<EdgeInfo>,
public fb: FormBuilder,
@Inject(WINDOW) protected window: Window) {
public fb: FormBuilder) {
super(store, fb, entityValue, entitiesTableConfigValue);
}
ngOnInit() {
this.edgeScope = this.entitiesTableConfig.componentsData.edgeScope;
this.entityForm.patchValue({
cloudEndpoint: this.window.location.origin
cloudEndpoint: window.location.origin
});
super.ngOnInit();
}
@ -94,7 +92,7 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
name: entity.name,
type: entity.type,
label: entity.label,
cloudEndpoint: entity.cloudEndpoint ? entity.cloudEndpoint : this.window.location.origin,
cloudEndpoint: entity.cloudEndpoint ? entity.cloudEndpoint : window.location.origin,
edgeLicenseKey: entity.edgeLicenseKey,
routingKey: entity.routingKey,
secret: entity.secret,

7
ui-ngx/src/app/shared/models/entity.models.ts

@ -45,6 +45,13 @@ export interface ImportEntityData {
timeseries: AttributeData[];
}
export interface EdgeImportEntityData extends ImportEntityData {
secret: string;
routingKey: string;
cloudEndpoint: string;
edgeLicenseKey: string;
}
export interface ImportEntitiesResultInfo {
create?: {
entity: number;

94
ui-ngx/src/assets/locale/locale.constant-de_DE.json

@ -731,7 +731,6 @@
"no-edges-matching": "Keine passenden Rand '{{entity}}' gefunden.",
"rulechain-templates": "Regelkettenvorlagen",
"add": "Rand hinzufügen",
"view": "Rand anzeigen",
"no-edges-text": "Kein Rand gefunden.",
"edge-details": "Details der Rand",
"add-edge-text": "Neue Rand hinzufügen",
@ -754,7 +753,6 @@
"id-copied-message": "Regelketten-ID wurde in die Zwischenablage kopiert",
"sync": "Sync Edge",
"sync-message": "Edge wurde synchronisiert",
"permissions": "Berechtigungen",
"edge-required": "Rand ist erforderlich.",
"edge-type": "Randtyp",
"edge-type-required": "Randtyp ist erforderlich.",
@ -777,14 +775,12 @@
"make-private-edge-text": "Nach der Bestätigung werden der Rand und dessen Daten privat und sind für andere nicht mehr zugänglich.",
"import": "Rand importieren",
"label": "Bezeichnung",
"assign-to-edge": "Assign to edge",
"assign-new-edge": "Neue Rand zuordnen",
"manage-edge-dashboards": "Rand-Dashboards verwalten",
"unassign-from-edge": "Rand zuweisen",
"dashboards": "Rand Dashboards",
"manage-edge-rulechains": "Randregelkette verwalten",
"rulechains": "Rand Regelketten",
"rulechain": "Rand Regelkette",
"edge-key": "Rand Schlüssel",
"copy-edge-key": "Rand Schlüssel kopieren",
"edge-key-copied-message": "Rand Schlüssel wurde in die Zwischenablage kopiert",
@ -797,18 +793,85 @@
"assets": "Rand Objekte",
"devices": "Objekte Geräte",
"entity-views": "Objekte Entitätsansichten",
"set-root-rulechain-text": "Bitte wählen Sie die Regelkette zur Wurzel rule chain für die Rand",
"set-root-rulechain-to-edges": "Regelkette zur Wurzel machen für die Rand",
"set-root-rulechain-to-edges-text": "Die Regelkette zur Wurzel für { count, plural, 1 {1 Rand} other {# Rand} } machen",
"status": "Von Rand empfangen",
"success": "Bereitgestellt",
"failed": "Steht aus",
"entity-id": "Entität ID",
"entity-info": "Entitätsinfo",
"event-action": "Ereignisaktion",
"load-entity-error": "Entität nicht gefunden. Fehler beim Laden der Informationen",
"unassign-edges-text": "Nach der Bestätigung werden alle ausgewählten Kanten nicht zugewiesen und sind für den Kunden nicht zugänglich.",
"unassign-edges-title": "Sind Sie sicher, dass Sie die Zuordnung aufheben möchten { count, plural, 1 {1 Rand} other {# Rand} }?"
"unassign-edges-title": "Sind Sie sicher, dass Sie die Zuordnung aufheben möchten { count, plural, 1 {1 Rand} other {# Rand} }?",
"edge-rulechains": "Kantenregelketten",
"edge-license-key-hint": "Um Ihre Lizenz zu erhalten, navigieren Sie zur <a href='https://thingsboard.io/pricing/?active=thingsboard-edge'arget='_blank'> Preisseite </a> und wählen Sie die beste Lizenzoption für Ihre aus Fall.",
"assignedToCustomer": "Dem Kunden zugewiesen",
"edge-public": "Edge ist öffentlich",
"search": "Kanten durchsuchen",
"selected-edges": "{Anzahl, Plural, 1 {1 Kante} andere {# Kanten}} ausgewählt",
"any-edge": "Beliebige Kante",
"dashboard": "Kanten-Dashboard",
"sync-process-started-successfully": "Synchronisierungsprozess erfolgreich gestartet!",
"delete-edges-action-title": "Löschen { count, plural, 1 {1 Rand} other {# Rand} }",
"set-root-rule-chain-text": "Bitte wählen Sie die Regelkette zur Wurzel rule chain für die Rand",
"set-root-rule-chain-to-edges": "Regelkette zur Wurzel machen für die Rand",
"set-root-rule-chain-to-edges-text": "Die Regelkette zur Wurzel für { count, plural, 1 {1 Rand} other {# Rand} } machen",
"status": "Von Rand empfangen",
"deployed": "Bereitgestellt",
"pending": "Steht aus",
"edge-file": "Edge-Datei",
"name-starts-with": "Der Kantenname beginnt mit",
"rulechain-template": "Regelkettenvorlage",
"unassign-edges-action-title": "Heben Sie die Zuordnung von {count, plural, 1 {1 edge} other {# edge}} vom Kunden auf",
"enter-edge-type": "Geben Sie den Kantentyp ein",
"no-edge-types-matching": "Es wurden keine Kantentypen gefunden, die mit '{{entitySubtype}}' übereinstimmen.",
"edge-type-list-empty": "Keine Kantentypen ausgewählt.",
"edge-types": "Kantentypen",
"license-key-hint": "Um Ihre Lizenz zu erhalten, navigieren Sie zur <a href='https://thingsboard.io/pricing/?active=thingsboard-edge'arget='_blank'> Preisseite </a> und wählen Sie die beste Lizenzoption für Ihre aus Fall.",
"cloud-endpoint-hint": "Edge erfordert HTTP-Zugriff auf die Cloud (ThingsBoard CE / PE), um den Lizenzschlüssel zu überprüfen. Bitte geben Sie die Cloud-URL an, zu der Edge eine Verbindung herstellen kann.",
"missing-related-rule-chains-title": "In Edge fehlen verwandte Regelketten.",
"missing-related-rule-chains-text": "Randregelkette (n) zugewiesen Verwenden Sie Regelknoten, die Nachrichten an Regelkette (n) weiterleiten, die dieser Kante nicht zugeordnet sind. <br> <br> Liste der fehlenden Regelketten: <br> {{missingRuleChains}}",
"downlinks": "Downlinks",
"no-downlinks-prompt": "Keine Downlinks gefunden",
"assigned-to-customer-widget": "Zugewiesen an: {{customerTitle}}",
"widget-datasource-error": "Dieses Widget unterstützt nur EDGE-Entitätsdatenquellen"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alarm",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
},
"error": {
"unable-to-connect": "Es konnte keine Verbindung zum Server hergestellt werden! Bitte überprüfen Sie Ihre Internetverbindung.",
@ -1405,7 +1468,12 @@
"unset-auto-assign-to-edge": "Deaktiviert die Zuordnung der Regelkette zu Kanten bei der Erstellung",
"unset-auto-assign-to-edge-title": "Möchten Sie die Kantenregelkette '{{ruleChainName}}' bei der Erstellung unbedingt den Kanten zuweisen?",
"unset-auto-assign-to-edge-text": "Nach der Bestätigung wird die Kantenregelkette bei der Erstellung nicht mehr automatisch den Kanten zugewiesen.",
"edge-template-root": "Vorlagenstamm"
"edge-template-root": "Vorlagenstamm",
"search": "Suchen Sie nach Regelketten",
"selected-rulechains": "{count, plural, 1 {1 Regelkette} andere {# Regelketten}} ausgewählt",
"open-rulechain": "Regelkette öffnen",
"assign-to-edge": "Rand zuweisen",
"edge-rulechain": "Kantenregelkette"
},
"rulenode": {
"details": "Details",

18
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -629,7 +629,8 @@
"default-customer-required": "Default customer is required in order to debug dashboard on Tenant level",
"search": "Search customers",
"selected-customers": "{ count, plural, 1 {1 customer} other {# customers} } selected",
"edges": "Customer edge instances"
"edges": "Customer edge instances",
"manage-edges": "Manage edges"
},
"datetime": {
"date-from": "Date from",
@ -1197,7 +1198,6 @@
"rulechains": "Rule chains",
"edge-rulechains": "Edge Rule chains",
"add": "Add Edge",
"view": "View Edge",
"no-edges-text": "No edges found",
"edge-details": "Edge details",
"add-edge-text": "Add new edge",
@ -1217,14 +1217,12 @@
"cloud-endpoint-required": "Cloud Endpoint is required.",
"cloud-endpoint-hint": "Edge requires HTTP(s) access to Cloud (ThingsBoard CE/PE) to verify the license key. Please specify Cloud URL that Edge is able to connect to.",
"description": "Description",
"entity-info": "Entity info",
"details": "Details",
"events": "Events",
"copy-id": "Copy Edge Id",
"id-copied-message": "Edge Id has been copied to clipboard",
"sync": "Sync Edge",
"sync-message": "Edge has been synchronized",
"permissions": "Permissions",
"edge-required": "Edge required",
"edge-type": "Edge type",
"edge-type-required": "Edge type is required.",
@ -1235,6 +1233,8 @@
"assign-to-customer-text": "Please select the customer to assign the edge(s)",
"assign-edge-to-customer": "Assign Edge(s) To Customer",
"assign-edge-to-customer-text": "Please select the edges to assign to the customer",
"assignedToCustomer": "Assigned to customer",
"edge-public": "Edge is public",
"assigned-to-customer": "Assigned to: {{customerTitle}}",
"unassign-from-customer": "Unassign from customer",
"assign-edges-text": "Assign { count, plural, 1 {1 edge} other {# edges} } to customer",
@ -1273,9 +1273,6 @@
"set-root-rule-chain-text": "Please select root rule chain for edge(s)",
"set-root-rule-chain-to-edges": "Set root rule chain for Edge(s)",
"set-root-rule-chain-to-edges-text": "Set root rule chain for { count, plural, 1 {1 edge} other {# edges} }",
"status": "Received by edge",
"success": "Deployed",
"failed": "Pending",
"search": "Search edges",
"selected-edges": "{ count, plural, 1 {1 edge} other {# edges} } selected",
"any-edge": "Any edge",
@ -1581,7 +1578,6 @@
"type-stats": "Statistics",
"type-debug-rule-node": "Debug",
"type-debug-rule-chain": "Debug",
"type-edge-event": "Downlink",
"no-events-prompt": "No events found",
"error": "Error",
"alarm": "Alarm",
@ -1981,9 +1977,9 @@
"access-token": "Access token",
"isgateway": "Is Gateway",
"description": "Description",
"edgeLicenseKey": "License Key",
"cloudEndpoint": "Cloud Endpoint",
"routingKey": "Edge key",
"edge-license-key": "License Key",
"cloud-endpoint": "Cloud Endpoint",
"routing-key": "Edge key",
"secret": "Edge secret"
},
"stepper-text":{

92
ui-ngx/src/assets/locale/locale.constant-es_ES.json

@ -753,7 +753,6 @@
"no-edges-matching": "No se encontraron bordes que coincidan con '{{entity}}'",
"rulechain-templates": "Plantillas, de cadena de reglas",
"add": "Agregar borde",
"view": "Ver borde",
"no-edges-text": "No se encontraron bordes",
"edge-details": "Detalles del borde",
"add-edge-text": "Agregar nuevo borde",
@ -776,12 +775,10 @@
"id-copied-message": "El ID de borde se ha copiado al portapapeles",
"sync": "Sinc Edge",
"sync-message": "Edge se ha sincronizado",
"permissions": "Permisos",
"edge-required": "Edge required",
"edge-type": "Type de la bordure",
"edge-type-required": "El tipo de borde es requerido.",
"select-edge-type": "Seleccionar tipo de borde",
"assign-to-edge": "Asignar al borde",
"assign-to-customer": "Asignar al cliente",
"assign-to-customer-text": "Seleccione el cliente para asignar los bordes",
"assign-edge-to-customer": "Asignar borde(s) al cliente",
@ -806,7 +803,6 @@
"dashboards": "Paneles de borde",
"manage-edge-rulechains": "Administrar cadenas de reglas de borde",
"rulechains": "Cadenas de regla de borde",
"rulechain": "Cadena de regla de borde",
"edge-key": "Clave de borde",
"copy-edge-key": "Copiar clave de borde",
"edge-key-copied-message": "La clave de borde se ha copiado al portapapeles",
@ -819,18 +815,83 @@
"assets": "Activos de borde",
"devices": "Dispositivos de borde",
"entity-views": "Vistas de entidad de borde",
"set-root-rulechain-text": "Seleccione la cadena de reglas raíz para los bordes",
"set-root-rulechain-to-edges": "Establecer la cadena de reglas raíz para Edge (s)",
"set-root-rulechain-to-edges-text": "Establecer la cadena de la regla raíz para {count, plural, 1 {1 borde} other {# bordes}}",
"status": "Recibido por borde",
"success": "Desplegada",
"failed": "Pendiente",
"entity-id": "ID de entidad",
"entity-info": "Entity info",
"event-action": "Información de la entidad",
"load-entity-error": "Entidad no encontrada. No se pudo cargar la información",
"unassign-edges-text": "Después de la confirmación de todos los bordes seleccionados, se anulará la asignación y el cliente no podrá acceder a ellos.",
"unassign-edges-title": "¿Está seguro de que desea anular la asignación de {count, plural, 1 {1 borde} other {# bordes}}?"
"unassign-edges-title": "¿Está seguro de que desea anular la asignación de {count, plural, 1 {1 borde} other {# bordes}}?",
"edge-rulechains": "Cadenas de reglas de borde",
"edge-license-key-hint": "Para obtener su licencia, vaya a la <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'> página de precios </a> y seleccione la mejor opción de licencia para su caso.",
"assignedToCustomer": "Asignada a la cliente",
"edge-public": "Edge es pública",
"set-root-rule-chain-text": "Seleccione la cadena de reglas raíz para los bordes",
"set-root-rule-chain-to-edges": "Establecer cadena de reglas raíz para Edge (s)",
"set-root-rule-chain-to-edges-text": "Establecer cadena de reglas raíz para {count, plural, 1 {1 edge} other {# ends}}",
"search": "Bordes de búsqueda",
"selected-edges": "{count, plural, 1 {1 borde} other {# bordes}} seleccionados",
"any-edge": "Cualquier bordee",
"dashboard": "Panel de control Edge",
"deployed": "Desplegada",
"pending": "Pending",
"sync-process-started-successfully": "¡El proceso de sincronización se inició correctamente!",
"edge-file": "Archivo de borde",
"name-starts-with": "Edge name starts with",
"rulechain-template": "Plantilla de cadena de reglas",
"unassign-edges-action-title": "Anular la asignación de {count, plural, 1 {1 borde} other {# bordes}} del cliente",
"enter-edge-type": "Ingrese el tipo de borde",
"no-edge-types-matching": "No se encontraron tipos de aristas que coincidan con '{{entitySubtype}}'.",
"edge-type-list-empty": "No se seleccionó ningún tipo de borde.",
"edge-types": "Tipos de bordes",
"license-key-hint": "Para obtener su licencia, vaya a la <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'> página de precios </a> y seleccione la mejor opción de licencia para su caso.",
"cloud-endpoint-hint": "Edge requiere acceso HTTP (s) a la nube (ThingsBoard CE / PE) para verificar la clave de licencia. Especifique la URL de la nube a la que Edge puede conectarse.",
"missing-related-rule-chains-title": "Al borde le faltan cadenas de reglas relacionadas",
"missing-related-rule-chains-text": "Asignado a la (s) cadena (s) de reglas de borde usa nodos de reglas que reenvían mensajes a cadenas de reglas que no están asignadas a este borde. <br> <br> Lista de cadenas de reglas faltantes: <br> {{missingRuleChains}}",
"downlinks": "Enlaces descendentes",
"no-downlinks-prompt": "No se encontraron enlaces descendentes",
"assigned-to-customer-widget": "Asignado a: {{customerTitle}}",
"widget-datasource-error": "Este widget solo admite la fuente de datos de la entidad EDGE"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alarm",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
},
"error": {
"unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.",
@ -1576,7 +1637,12 @@
"unset-auto-assign-to-edge": "Desmarcar asignar cadena de reglas a los bordes en la creación",
"unset-auto-assign-to-edge-title": "¿Está seguro de que desea anular la asignación de la cadena de reglas de borde '{{ruleChainName}}' a los bordes en la creación?",
"unset-auto-assign-to-edge-text": "Después de la confirmación, la cadena de reglas de borde ya no se asignará automáticamente a los bordes en la creación.",
"edge-template-root": "Raíz de plantilla"
"edge-template-root": "Raíz de plantilla",
"search": "Cadenas de reglas de búsqueda",
"selected-rulechains": "{count, plural, 1 {1 cadena de reglas} otras {# cadenas de reglas}} seleccionadas",
"open-rulechain": "Cadena de reglas abierta",
"assign-to-edge": "Asignar a Edge",
"edge-rulechain": "Cadena de regla de borde"
},
"rulenode": {
"details": "Detalles",

89
ui-ngx/src/assets/locale/locale.constant-fr_FR.json

@ -749,7 +749,6 @@
"no-edges-matching": "Aucun bordure correspondant à {{entity}} n'a été trouvé.",
"rulechain-templates": "Modèles de chaîne de règles",
"add": "Ajouter un bordure",
"view": "Afficher la bordure",
"no-edges-text": "Aucun bordure trouvé",
"edge-details": "Détails de la bordure",
"add-edge-text": "Ajouter une nouveau bordure",
@ -772,12 +771,10 @@
"id-copied-message": "Id de la bordure a été copié dans le presse-papier",
"sync": "Sync Edge",
"sync-message": "Edge a été synchronisé",
"permissions": "Autorisations",
"edge-required": "Bordure est requise",
"edge-type": "Type de la bordure",
"edge-type-required": "Type de la bordure est requise.",
"select-edge-type": "Selectionner un type de la bordure",
"assign-to-edge": "Attribuer au bord",
"assign-to-customer": "Attribuer au client",
"assign-to-customer-text": "Veuillez sélectionner la bordure pour attribuer le ou les dispositifs",
"assign-edge-to-customer": "Attribuer la bordure au client",
@ -802,7 +799,6 @@
"dashboards": "Tableau de bord de la bordure",
"manage-edge-rulechains": "Gérer les chaînes de règles",
"rulechains": "Chaînes de règles de la bordure",
"rulechain": "Chaîne de règles de la bordure",
"edge-key": "Clé de la bordure",
"copy-edge-key": "Copier clé de la bordure",
"edge-key-copied-message": "Clé de la bordure a été copié dans le presse-papier",
@ -815,18 +811,79 @@
"assets": "Actifs de la bordure",
"devices": "Dispositifs de la bordure",
"entity-views": "Vues de l'entité bordure",
"set-root-rulechain-text": "Veuillez sélectionner la chaîne de règles racine pour les bordure(s)",
"set-rootrule-chain-to-edges": "Définir la chaîne de règles racine pour bordure(s)",
"set-root-rulechain-to-edges-text": "Définir la chaîne de règles racine pour {count, plural, 1 {1 bordure} other {# bordures} }",
"status": "Reçu par bord",
"success": "Déployée",
"failed": "En attente",
"entity-id": "ID d'entité",
"entity-info": "Informations sur l'entité",
"event-action": "Action d'événement",
"load-entity-error": "Entité introuvable. Échec du chargement des informations",
"unassign-edges-text": "Après la confirmation, tous les bordures sélectionnés ne seront plus attribués et ne seront pas accessibles par le client.",
"unassign-edges-title": "Voulez-vous vraiment annuler l'attribution de {count, plural, 1 {1 bordure} other {# bordures}}?"
"unassign-edges-title": "Voulez-vous vraiment annuler l'attribution de {count, plural, 1 {1 bordure} other {# bordures}}?",
"edge-file": "Fichier Edge",
"edge-rulechains": "Chaînes de règles Edge",
"name-starts-with": "Le nom du bord commence par",
"edge-license-key-hint": "Pour obtenir votre licence, accédez à la <a href='https://thingsboard.io/pricing/?active=thingsboard-edge' target='_blank'> page de tarification</a> and select the best license option for your case.",
"cloud-endpoint-hint": "Edge nécessite un accès HTTP (s) au Cloud (ThingsBoard CE / PE) pour vérifier la clé de licence. Veuillez spécifier l'URL du cloud à laquelle Edge peut se connecter.",
"assignedToCustomer": "Attribué au client",
"edge-public": "Edge est public",
"set-root-rule-chain-text": "Veuillez sélectionner la chaîne de règles racine pour les arêtes",
"set-root-rule-chain-to-edges": "Définir la chaîne de règles racine pour Edge (s)",
"set-root-rule-chain-to-edges-text": "Définir la chaîne de règles racine pour {count, plural, 1 {1 edge} other {# edges}}",
"search": "Rechercher les bords",
"selected-edges": "{count, plural, 1 {1 edge} other {# bords}} sélectionné",
"any-edge": "Tout bord",
"no-edge-types-matching": "Aucun type d'arête correspondant à \"{{entitySubtype}}\" n'a été trouvé.",
"edge-type-list-empty": "Aucun type d'arête sélectionné.",
"edge-types": "Types de bords",
"dashboard": "Tableau de bord Edge",
"enter-edge-type": "Entrez le type d'arête",
"deployed": "Déployé",
"pending": "En attente",
"downlinks": "Liens descendants",
"no-downlinks-prompt": "Aucun lien descendant trouvé",
"sync-process-started-successfully": "Le processus de synchronisation a démarré avec succès!",
"missing-related-rule-chains-title": "Edge n'a pas de chaîne (s) de règles associées",
"missing-related-rule-chains-text": "Les chaînes de règles affectées aux tronçons utilisent des nœuds de règles qui transfèrent les messages vers les chaînes de règles non affectées à ce tronçon. <br> <br> Liste des chaînes de règles manquantes: <br> {{missingRuleChains}}",
"widget-datasource-error": "Ce widget prend en charge uniquement la source de données d'entité EDGE"
},
"edge-event": {
"type-dashboard": "Dashboard",
"type-asset": "Asset",
"type-device": "Device",
"type-device-profile": "Device Profile",
"type-entity-view": "Entity View",
"type-alarm": "Alarm",
"type-rule-chain": "Rule Chain",
"type-rule-chain-metadata": "Rule Chain Metadata",
"type-edge": "Edge",
"type-entity-group": "Entity Group",
"type-scheduler-event": "Scheduler Event",
"type-white-labeling": "White Labeling",
"type-login-white-labeling": "White Labeling Login",
"type-user": "User",
"type-tenant": "Tenant",
"type-customer": "Customer",
"type-custom-translation": "Custom Translation",
"type-relation": "Relation",
"type-widgets-bundle": "Widgets Bundle",
"type-widgets-type": "Widgets Type",
"type-admin-settings": "Admin Settings",
"action-type-added": "Added",
"action-type-deleted": "Deleted",
"action-type-updated": "Updated",
"action-type-post-attributes": "Post Attributes",
"action-type-attributes-updated": "Attributes Updated",
"action-type-attributes-deleted": "Attributes Deleted",
"action-type-timeseries-updated": "Timeseries Updated",
"action-type-credentials-updated": "Credentials Updated",
"action-type-assigned-to-customer": "Assigned to Customer",
"action-type-unassigned-from-customer": "Unassigned from Customer",
"action-type-relation-add-or-update": "Relation Add or Update",
"action-type-relation-deleted": "Relation Deleted",
"action-type-rpc-call": "RPC Call",
"action-type-alarm-ack": "Alarm Ack",
"action-type-alarm-clear": "Alarm Clear",
"action-type-assigned-to-edge": "Assigned to Edge",
"action-type-unassigned-from-edge": "Unassigned from Edge",
"action-type-credentials-request": "Credentials Request",
"action-type-entity-merge-request": "Entity Merge Request"
},
"entity": {
"add-alias": "Ajouter un alias d'entité",
@ -1450,7 +1507,13 @@
"unset-auto-assign-to-edge": "Non défini, attribuer une chaîne de règles aux arêtes lors de la création",
"unset-auto-assign-to-edge-title": "Voulez-vous vraiment annuler l'attribution de la chaîne de règles d'arête \"{{ruleChainName}}\" aux arêtes lors de la création?",
"unset-auto-assign-to-edge-text": "Après la confirmation, la chaîne de règles d'arêtes ne sera plus automatiquement affectée aux arêtes lors de la création.",
"edge-template-root": "Racine du modèle"
"edge-template-root": "Racine du modèle",
"search": "Rechercher des chaînes de règles",
"selected-rulechains": "{count, plural, 1 {1 rule chain} other {# rule chains}} sélectionné",
"open-rulechain": "Chaîne de règles ouverte",
"assign-to-edge": "Attribuer à Edge",
"edge-rulechain": "Chaîne de règles Edge",
"unassign-rulechains-from-edge-title": "Voulez-vous vraiment annuler l'attribution de {count, plural, 1 {1 rulechain} other {# rulechains}}?"
},
"rulenode": {
"add": "Ajouter un noeud de règle",

Loading…
Cancel
Save