Browse Source

Add bulk provision support label (#2096)

* Add to asset support label

* Add support import label

* Add support update entity type and label

* Add translate asset label
pull/2105/head
Vladyslav 7 years ago
committed by Igor Kulikov
parent
commit
c36af7311e
  1. 5
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  2. 9
      application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
  3. 9
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  4. 12
      common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java
  5. 1
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  6. 8
      dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java
  7. 8
      dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java
  8. 3
      dao/src/main/resources/cassandra/schema-entities.cql
  9. 1
      dao/src/main/resources/sql/schema-entities.sql
  10. 38
      ui/src/app/api/entity.service.js
  11. 4
      ui/src/app/asset/asset-fieldset.tpl.html
  12. 4
      ui/src/app/common/types.constant.js
  13. 6
      ui/src/app/import-export/import-dialog-csv.controller.js
  14. 6
      ui/src/app/import-export/table-columns-assignment.directive.js
  15. 1
      ui/src/app/import-export/table-columns-assignment.tpl.html
  16. 3
      ui/src/app/locale/locale.constant-cs_CZ.json
  17. 3
      ui/src/app/locale/locale.constant-de_DE.json
  18. 4
      ui/src/app/locale/locale.constant-en_US.json
  19. 3
      ui/src/app/locale/locale.constant-es_ES.json
  20. 3
      ui/src/app/locale/locale.constant-fa_IR.json
  21. 3
      ui/src/app/locale/locale.constant-fr_FR.json
  22. 3
      ui/src/app/locale/locale.constant-it_IT.json
  23. 3
      ui/src/app/locale/locale.constant-ja_JA.json
  24. 4
      ui/src/app/locale/locale.constant-ru_RU.json
  25. 3
      ui/src/app/locale/locale.constant-tr_TR.json
  26. 6
      ui/src/app/locale/locale.constant-uk_UA.json
  27. 3
      ui/src/app/locale/locale.constant-zh_CN.json

5
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -119,6 +119,11 @@ public class ThingsboardInstallService {
case "2.4.0":
log.info("Upgrading ThingsBoard from version 2.4.0 to 2.4.1 ...");
case "2.4.1":
log.info("Upgrading ThingsBoard from version 2.4.1 to 2.4.2 ...");
databaseUpgradeService.upgradeDatabase("2.4.1");
log.info("Updating system data...");
systemDataLoaderService.deleteSystemWidgetBundle("charts");

9
application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java

@ -267,6 +267,15 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
} catch (InvalidQueryException e) {}
log.info("Schema updated.");
break;
case "2.4.1":
log.info("Updating schema ...");
String updateAssetTableStmt = "alter table asset add label text";
try {
cluster.getSession().execute(updateAssetTableStmt);
Thread.sleep(2500);
} catch (InvalidQueryException e) {}
log.info("Schema updated.");
break;
default:
throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion);
}

9
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -176,6 +176,15 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
log.info("Schema updated.");
}
break;
case "2.4.1":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Updating schema ...");
try {
conn.createStatement().execute("ALTER TABLE asset ADD COLUMN label varchar(255)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
} catch (Exception e) {}
log.info("Schema updated.");
}
break;
default:
throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
}

12
common/data/src/main/java/org/thingsboard/server/common/data/asset/Asset.java

@ -31,6 +31,7 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
private CustomerId customerId;
private String name;
private String type;
private String label;
public Asset() {
super();
@ -46,6 +47,7 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
this.customerId = asset.getCustomerId();
this.name = asset.getName();
this.type = asset.getType();
this.label = asset.getLabel();
}
public TenantId getTenantId() {
@ -81,6 +83,14 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
this.type = type;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String getSearchText() {
return getName();
@ -97,6 +107,8 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
builder.append(name);
builder.append(", type=");
builder.append(type);
builder.append(", label=");
builder.append(label);
builder.append(", additionalInfo=");
builder.append(getAdditionalInfo());
builder.append(", createdTime=");

1
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -197,6 +197,7 @@ public class ModelConstants {
public static final String ASSET_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String ASSET_NAME_PROPERTY = "name";
public static final String ASSET_TYPE_PROPERTY = "type";
public static final String ASSET_LABEL_PROPERTY = "label";
public static final String ASSET_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text";

8
dao/src/main/java/org/thingsboard/server/dao/model/nosql/AssetEntity.java

@ -37,6 +37,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
@ -64,6 +65,9 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
@Column(name = ASSET_NAME_PROPERTY)
private String name;
@Column(name = ASSET_LABEL_PROPERTY)
private String label;
@Column(name = SEARCH_TEXT_PROPERTY)
private String searchText;
@ -86,6 +90,7 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
}
this.name = asset.getName();
this.type = asset.getType();
this.label = asset.getLabel();
this.additionalInfo = asset.getAdditionalInfo();
}
@ -163,8 +168,9 @@ public final class AssetEntity implements SearchTextEntity<Asset> {
}
asset.setName(name);
asset.setType(type);
asset.setLabel(label);
asset.setAdditionalInfo(additionalInfo);
return asset;
}
}
}

8
dao/src/main/java/org/thingsboard/server/dao/model/sql/AssetEntity.java

@ -40,6 +40,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_NAME_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TENANT_ID_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_TYPE_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.ASSET_LABEL_PROPERTY;
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
@Data
@ -61,6 +62,9 @@ public final class AssetEntity extends BaseSqlEntity<Asset> implements SearchTex
@Column(name = ASSET_TYPE_PROPERTY)
private String type;
@Column(name = ASSET_LABEL_PROPERTY)
private String label;
@Column(name = SEARCH_TEXT_PROPERTY)
private String searchText;
@ -84,6 +88,7 @@ public final class AssetEntity extends BaseSqlEntity<Asset> implements SearchTex
}
this.name = asset.getName();
this.type = asset.getType();
this.label = asset.getLabel();
this.additionalInfo = asset.getAdditionalInfo();
}
@ -113,8 +118,9 @@ public final class AssetEntity extends BaseSqlEntity<Asset> implements SearchTex
}
asset.setName(name);
asset.setType(type);
asset.setLabel(label);
asset.setAdditionalInfo(additionalInfo);
return asset;
}
}
}

3
dao/src/main/resources/cassandra/schema-entities.cql

@ -244,6 +244,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.asset (
customer_id timeuuid,
name text,
type text,
label text,
search_text text,
additional_info text,
PRIMARY KEY (id, tenant_id, customer_id, type)
@ -711,4 +712,4 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_ent
AND search_text IS NOT NULL
AND id IS NOT NULL
PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id, type)
WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC);
WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC);

1
dao/src/main/resources/sql/schema-entities.sql

@ -42,6 +42,7 @@ CREATE TABLE IF NOT EXISTS asset (
additional_info varchar,
customer_id varchar(31),
name varchar(255),
label varchar(255),
search_text varchar(255),
tenant_id varchar(31),
type varchar(255)

38
ui/src/app/api/entity.service.js

@ -1130,19 +1130,12 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
let statisticalInfo = {};
let newEntity = {
name: entityParameters.name,
type: entityParameters.type
type: entityParameters.type,
label: entityParameters.label
};
let promise;
switch (entityType) {
case types.entityType.device:
promise = deviceService.saveDevice(newEntity, config);
break;
case types.entityType.asset:
promise = assetService.saveAsset(newEntity, true, config);
break;
}
let saveEntityPromise = getEntitySavePromise(entityType, newEntity, config);
promise.then(function success(response) {
saveEntityPromise.then(function success(response) {
saveEntityRelation(entityType, response.id, entityParameters, config).then(function success() {
statisticalInfo.create = {
entity: 1
@ -1166,7 +1159,15 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
break;
}
findIdEntity.then(function success(response) {
saveEntityRelation(entityType, response.id, entityParameters, config).then(function success() {
let promises = [];
if(response.label !== entityParameters.label || response.type !== entityParameters.type){
response.label = entityParameters.label;
response.type = entityParameters.type;
promises.push(getEntitySavePromise(entityType, response, config));
}
promises.push(saveEntityRelation(entityType, response.id, entityParameters, config));
$q.all(promises).then(function success() {
statisticalInfo.update = {
entity: 1
};
@ -1193,6 +1194,19 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
return deferred.promise;
}
function getEntitySavePromise(entityType, newEntity, config) {
let promise;
switch (entityType) {
case types.entityType.device:
promise = deviceService.saveDevice(newEntity, config);
break;
case types.entityType.asset:
promise = assetService.saveAsset(newEntity, true, config);
break;
}
return promise;
}
function getRelatedEntity(entityId, keys, typeTranslatePrefix) {
var deferred = $q.defer();
getEntityPromise(entityId.entityType, entityId.id, {ignoreLoading: true}).then(

4
ui/src/app/asset/asset-fieldset.tpl.html

@ -63,6 +63,10 @@
ng-model="asset.type"
entity-type="types.entityType.asset">
</tb-entity-subtype-autocomplete>
<md-input-container class="md-block">
<label translate>asset.label</label>
<input name="label" ng-model="asset.label">
</md-input-container>
<md-input-container class="md-block">
<label translate>asset.description</label>
<textarea ng-model="asset.additionalInfo.description" rows="2"></textarea>

4
ui/src/app/common/types.constant.js

@ -369,6 +369,10 @@ export default angular.module('thingsboard.types', [])
name: 'import.column-type.type',
value: 'type'
},
label: {
name: 'import.column-type.label',
value: 'label'
},
clientAttribute: {
name: 'import.column-type.client-attribute',
value: 'CLIENT_ATTRIBUTE'

6
ui/src/app/import-export/import-dialog-csv.controller.js

@ -98,7 +98,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
vm.columnsParam = [];
var columnParam = {};
for (var i = 0; i < parseData.headers.length; i++) {
if (vm.importParameters.isHeader && parseData.headers[i].search(/^(name|type)$/im) === 0) {
if (vm.importParameters.isHeader && parseData.headers[i].search(/^(name|type|label)$/im) === 0) {
columnParam = {
type: types.importEntityColumnType[parseData.headers[i].toLowerCase()].value,
key: parseData.headers[i].toLowerCase(),
@ -126,6 +126,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
var entityData = {
name: "",
type: "",
label: "",
accessToken: "",
attributes: {
server: [],
@ -162,6 +163,9 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
case types.importEntityColumnType.type.value:
entityData.type = importData.rows[i][j];
break;
case types.importEntityColumnType.label.value:
entityData.label = importData.rows[i][j];
break;
}
}
entitiesData.push(entityData);

6
ui/src/app/import-export/table-columns-assignment.directive.js

@ -44,6 +44,7 @@ function TableColumnsAssignmentController($scope, types, $timeout) {
vm.columnTypes.name = types.importEntityColumnType.name;
vm.columnTypes.type = types.importEntityColumnType.type;
vm.columnTypes.label = types.importEntityColumnType.label;
switch (vm.entityType) {
case types.entityType.device:
@ -62,6 +63,7 @@ function TableColumnsAssignmentController($scope, types, $timeout) {
if (newVal) {
var isSelectName = false;
var isSelectType = false;
var isSelectLabel = false;
var isSelectCredentials = false;
for (var i = 0; i < newVal.length; i++) {
switch (newVal[i].type) {
@ -71,6 +73,9 @@ function TableColumnsAssignmentController($scope, types, $timeout) {
case types.importEntityColumnType.type.value:
isSelectType = true;
break;
case types.importEntityColumnType.label.value:
isSelectLabel = true;
break;
case types.importEntityColumnType.accessToken.value:
isSelectCredentials = true;
break;
@ -84,6 +89,7 @@ function TableColumnsAssignmentController($scope, types, $timeout) {
$timeout(function () {
vm.columnTypes.name.disable = isSelectName;
vm.columnTypes.type.disable = isSelectType;
vm.columnTypes.label.disable = isSelectLabel;
if (angular.isDefined(vm.columnTypes.accessToken)) {
vm.columnTypes.accessToken.disable = isSelectCredentials;
}

1
ui/src/app/import-export/table-columns-assignment.tpl.html

@ -41,6 +41,7 @@
<md-input-container md-no-float
ng-if="column.type != vm.columnTypes.name.value &&
column.type != vm.columnTypes.type.value &&
column.type != vm.columnTypes.label.value &&
column.type != vm.columnTypes.accessToken.value">
<input required name="columnKeyName"
placeholder="{{ 'import.column-value' | translate }}"

3
ui/src/app/locale/locale.constant-cs_CZ.json

@ -246,7 +246,8 @@
"select-asset": "Vybrat aktivum",
"no-assets-matching": "Žádná aktiva odpovídající '{{entity}}' nebyla nalezena.",
"asset-required": "Aktivum je povinné",
"name-starts-with": "Název aktiva začíná"
"name-starts-with": "Název aktiva začíná",
"label": "Název"
},
"attribute": {
"attributes": "Atributy",

3
ui/src/app/locale/locale.constant-de_DE.json

@ -267,7 +267,8 @@
"select-asset": "Objekt auswählen",
"no-assets-matching": "Es wurden keine zu '{{entity}}' passenden Objekte gefunden.",
"asset-required": "Objekt ist erforderlich",
"name-starts-with": "Name des Objekts beginnt mit"
"name-starts-with": "Name des Objekts beginnt mit",
"label": "Bezeichnung"
},
"attribute": {
"attributes": "Eigenschaften",

4
ui/src/app/locale/locale.constant-en_US.json

@ -271,7 +271,8 @@
"asset-required": "Asset is required",
"name-starts-with": "Asset name starts with",
"import": "Import assets",
"asset-file": "Asset file"
"asset-file": "Asset file",
"label": "Label"
},
"attribute": {
"attributes": "Attributes",
@ -1139,6 +1140,7 @@
"column-type": {
"name": "Name",
"type": "Type",
"label": "Label",
"column-type": "Column type",
"client-attribute": "Client attribute",
"shared-attribute": "Shared attribute",

3
ui/src/app/locale/locale.constant-es_ES.json

@ -271,7 +271,8 @@
"asset-required": "El activo es requerido",
"name-starts-with": "El nombre del activo comienza con",
"import": "Importar activos",
"asset-file": "Archivo del activo"
"asset-file": "Archivo del activo",
"label": "Etiqueta"
},
"attribute": {
"attributes": "Atributos",

3
ui/src/app/locale/locale.constant-fa_IR.json

@ -246,7 +246,8 @@
"select-asset": "انتخاب دارايي",
"no-assets-matching": ".يافت نشد '{{entity}}' هيچ دارايي منطبق بر",
"asset-required": "دارايي مود نياز است",
"name-starts-with": "نام دارايي شروع مي شود با"
"name-starts-with": "نام دارايي شروع مي شود با",
"label": "برچسب"
},
"attribute": {
"attributes": "ويژگي ها",

3
ui/src/app/locale/locale.constant-fr_FR.json

@ -271,7 +271,8 @@
"unassign-assets-text": "Après la confirmation, tous les actifs sélectionnés ne seront pas attribués et ne seront pas accessibles au client.",
"unassign-assets-title": "Êtes-vous sûr de vouloir retirer l'attribution de {count, plural, 1 {1 asset} other {# assets}}?",
"unassign-from-customer": "Retirer du client",
"view-assets": "Afficher les actifs"
"view-assets": "Afficher les actifs",
"label": "Label"
},
"attribute": {
"add": "Ajouter un attribut",

3
ui/src/app/locale/locale.constant-it_IT.json

@ -268,7 +268,8 @@
"select-asset": "Seleziona asset",
"no-assets-matching": "Nessun asset corrispondente a '{{entity}}' è stato trovato.",
"asset-required": "Asset obbligatorio",
"name-starts-with": "Asset con nome che inizia per"
"name-starts-with": "Asset con nome che inizia per",
"label": "Etichetta"
},
"attribute": {
"attributes": "Attributi",

3
ui/src/app/locale/locale.constant-ja_JA.json

@ -236,7 +236,8 @@
"select-asset": "アセットを選択",
"no-assets-matching": "'{{entity}}'発見されました。",
"asset-required": "資産が必要です",
"name-starts-with": "アセット名はで始まります"
"name-starts-with": "アセット名はで始まります",
"label": "ラベル"
},
"attribute": {
"attributes": "属性",

4
ui/src/app/locale/locale.constant-ru_RU.json

@ -250,7 +250,8 @@
"asset-required": "Актив обязателен",
"name-starts-with": "Название актива, начинающееся с",
"import": "Импортировать активы",
"asset-file": "Файл с активами"
"asset-file": "Файл с активами",
"label": "Метка"
},
"attribute": {
"attributes": "Атрибуты",
@ -1113,6 +1114,7 @@
"column-type": {
"name": "Название",
"type": "Тип",
"label": "Метка",
"column-type": "Тип колонки",
"client-attribute": "Клиентский атрибут",
"shared-attribute": "Общий атрибут",

3
ui/src/app/locale/locale.constant-tr_TR.json

@ -236,7 +236,8 @@
"select-asset": "Varlık seç",
"no-assets-matching": "'{{entity}}' isimli varlık bulunamadı.",
"asset-required": "Varlık gerekli",
"name-starts-with": "... ile başlayan varlık adı"
"name-starts-with": "... ile başlayan varlık adı",
"label": "Etiket"
},
"attribute": {
"attributes": "Öznitelikler",

6
ui/src/app/locale/locale.constant-uk_UA.json

@ -280,7 +280,8 @@
"list-of-groups": "{ count, plural, 1 {Одна група активів} other {Список # груп активів} }",
"group-name-starts-with": "Групи активів, чиї імена починаються з '{{prefix}}'",
"import": "Імпортувати активи",
"asset-file": "Файл з активами"
"asset-file": "Файл з активами",
"label": "Мітка"
},
"attribute": {
"attributes": "Атрибути",
@ -1365,6 +1366,7 @@
"column-type": {
"name": "Назва",
"type": "Тип",
"label": "Мітка",
"column-type": "Тип колонки",
"client-attribute": "Атрибут клієнта",
"shared-attribute": "Спільний атрибут",
@ -2343,4 +2345,4 @@
"cs_CZ": "Чеська"
}
}
}
}

3
ui/src/app/locale/locale.constant-zh_CN.json

@ -241,7 +241,8 @@
"select-asset": "选择资产",
"no-assets-matching": "没有找到匹配 '{{entity}}' 的资产。",
"asset-required": "资产必填",
"name-starts-with": "资产名称以此开头"
"name-starts-with": "资产名称以此开头",
"label": "标签"
},
"attribute": {
"attributes": "属性",

Loading…
Cancel
Save