Commit 68e9844f535c7ec6e5527143d696157319b11389

Authored by Vladyslav_Prykhodko
1 parent 6148dafa

Add device

@@ -30,7 +30,9 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -30,7 +30,9 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
30 subscribeForEntityAttributes: subscribeForEntityAttributes, 30 subscribeForEntityAttributes: subscribeForEntityAttributes,
31 unsubscribeForEntityAttributes: unsubscribeForEntityAttributes, 31 unsubscribeForEntityAttributes: unsubscribeForEntityAttributes,
32 saveEntityAttributes: saveEntityAttributes, 32 saveEntityAttributes: saveEntityAttributes,
33 - deleteEntityAttributes: deleteEntityAttributes 33 + deleteEntityAttributes: deleteEntityAttributes,
  34 + saveEntityTimeseries: saveEntityTimeseries,
  35 + deleteEntityTimeseries: deleteEntityTimeseries
34 } 36 }
35 37
36 return service; 38 return service;
@@ -212,7 +214,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -212,7 +214,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
212 } 214 }
213 } 215 }
214 216
215 - function saveEntityAttributes(entityType, entityId, attributeScope, attributes) { 217 + function saveEntityAttributes(entityType, entityId, attributeScope, attributes, config) {
  218 + config = config || {};
216 var deferred = $q.defer(); 219 var deferred = $q.defer();
217 var attributesData = {}; 220 var attributesData = {};
218 var deleteAttributes = []; 221 var deleteAttributes = [];
@@ -229,7 +232,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -229,7 +232,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
229 } 232 }
230 if (Object.keys(attributesData).length) { 233 if (Object.keys(attributesData).length) {
231 var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope; 234 var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope;
232 - $http.post(url, attributesData).then(function success(response) { 235 + $http.post(url, attributesData, config).then(function success(response) {
233 if (deleteEntityAttributesPromise) { 236 if (deleteEntityAttributesPromise) {
234 deleteEntityAttributesPromise.then( 237 deleteEntityAttributesPromise.then(
235 function success() { 238 function success() {
@@ -260,6 +263,55 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -260,6 +263,55 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
260 return deferred.promise; 263 return deferred.promise;
261 } 264 }
262 265
  266 + function saveEntityTimeseries(entityType, entityId, timeseriesScope, timeseries, config) {
  267 + config = config || {};
  268 + var deferred = $q.defer();
  269 + var timeseriesData = {};
  270 + var deleteTimeseries = [];
  271 + for (var a=0; a<timeseries.length;a++) {
  272 + if (angular.isDefined(timeseries[a].value) && timeseries[a].value !== null) {
  273 + timeseriesData[timeseries[a].key] = timeseries[a].value;
  274 + } else {
  275 + deleteTimeseries.push(timeseries[a]);
  276 + }
  277 + }
  278 + var deleteEntityTimeseriesPromise;
  279 + if (deleteTimeseries.length) {
  280 + deleteEntityTimeseriesPromise = deleteEntityTimeseries(entityType, entityId, deleteTimeseries);
  281 + }
  282 + if (Object.keys(timeseriesData).length) {
  283 + var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/' + timeseriesScope;
  284 + $http.post(url, timeseriesData, config).then(function success(response) {
  285 + if (deleteEntityTimeseriesPromise) {
  286 + deleteEntityTimeseriesPromise.then(
  287 + function success() {
  288 + deferred.resolve(response.data);
  289 + },
  290 + function fail() {
  291 + deferred.reject();
  292 + }
  293 + )
  294 + } else {
  295 + deferred.resolve(response.data);
  296 + }
  297 + }, function fail() {
  298 + deferred.reject();
  299 + });
  300 + } else if (deleteEntityTimeseriesPromise) {
  301 + deleteEntityTimeseriesPromise.then(
  302 + function success() {
  303 + deferred.resolve();
  304 + },
  305 + function fail() {
  306 + deferred.reject();
  307 + }
  308 + )
  309 + } else {
  310 + deferred.resolve();
  311 + }
  312 + return deferred.promise;
  313 + }
  314 +
263 function deleteEntityAttributes(entityType, entityId, attributeScope, attributes) { 315 function deleteEntityAttributes(entityType, entityId, attributeScope, attributes) {
264 var deferred = $q.defer(); 316 var deferred = $q.defer();
265 var keys = ''; 317 var keys = '';
@@ -278,5 +330,22 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) @@ -278,5 +330,22 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
278 return deferred.promise; 330 return deferred.promise;
279 } 331 }
280 332
  333 + function deleteEntityTimeseries(entityType, entityId, timeseries) {
  334 + var deferred = $q.defer();
  335 + var keys = '';
  336 + for (var i = 0; i < timeseries.length; i++) {
  337 + if (i > 0) {
  338 + keys += ',';
  339 + }
  340 + keys += timeseries[i].key;
  341 + }
  342 + var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys;
  343 + $http.delete(url).then(function success() {
  344 + deferred.resolve();
  345 + }, function fail() {
  346 + deferred.reject();
  347 + });
  348 + return deferred.promise;
  349 + }
281 350
282 } 351 }
@@ -31,6 +31,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -31,6 +31,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
31 getDeviceCredentials: getDeviceCredentials, 31 getDeviceCredentials: getDeviceCredentials,
32 getTenantDevices: getTenantDevices, 32 getTenantDevices: getTenantDevices,
33 saveDevice: saveDevice, 33 saveDevice: saveDevice,
  34 + saveDeviceParameters: saveDeviceParameters,
34 saveDeviceCredentials: saveDeviceCredentials, 35 saveDeviceCredentials: saveDeviceCredentials,
35 unassignDeviceFromCustomer: unassignDeviceFromCustomer, 36 unassignDeviceFromCustomer: unassignDeviceFromCustomer,
36 makeDevicePublic: makeDevicePublic, 37 makeDevicePublic: makeDevicePublic,
@@ -42,7 +43,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -42,7 +43,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
42 sendOneWayRpcCommand: sendOneWayRpcCommand, 43 sendOneWayRpcCommand: sendOneWayRpcCommand,
43 sendTwoWayRpcCommand: sendTwoWayRpcCommand, 44 sendTwoWayRpcCommand: sendTwoWayRpcCommand,
44 findByQuery: findByQuery, 45 findByQuery: findByQuery,
45 - getDeviceTypes: getDeviceTypes 46 + getDeviceTypes: getDeviceTypes,
  47 + findByName: findByName
46 } 48 }
47 49
48 return service; 50 return service;
@@ -124,7 +126,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -124,7 +126,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
124 if (!config) { 126 if (!config) {
125 config = {}; 127 config = {};
126 } 128 }
127 - config = Object.assign(config, { ignoreErrors: ignoreErrors }); 129 + config = Object.assign(config, {ignoreErrors: ignoreErrors});
128 $http.get(url, config).then(function success(response) { 130 $http.get(url, config).then(function success(response) {
129 deferred.resolve(response.data); 131 deferred.resolve(response.data);
130 }, function fail(response) { 132 }, function fail(response) {
@@ -136,8 +138,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -136,8 +138,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
136 function getDevices(deviceIds, config) { 138 function getDevices(deviceIds, config) {
137 var deferred = $q.defer(); 139 var deferred = $q.defer();
138 var ids = ''; 140 var ids = '';
139 - for (var i=0;i<deviceIds.length;i++) {  
140 - if (i>0) { 141 + for (var i = 0; i < deviceIds.length; i++) {
  142 + if (i > 0) {
141 ids += ','; 143 ids += ',';
142 } 144 }
143 ids += deviceIds[i]; 145 ids += deviceIds[i];
@@ -146,11 +148,11 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -146,11 +148,11 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
146 $http.get(url, config).then(function success(response) { 148 $http.get(url, config).then(function success(response) {
147 var devices = response.data; 149 var devices = response.data;
148 devices.sort(function (device1, device2) { 150 devices.sort(function (device1, device2) {
149 - var id1 = device1.id.id;  
150 - var id2 = device2.id.id;  
151 - var index1 = deviceIds.indexOf(id1);  
152 - var index2 = deviceIds.indexOf(id2);  
153 - return index1 - index2; 151 + var id1 = device1.id.id;
  152 + var id2 = device2.id.id;
  153 + var index1 = deviceIds.indexOf(id1);
  154 + var index2 = deviceIds.indexOf(id2);
  155 + return index1 - index2;
154 }); 156 });
155 deferred.resolve(devices); 157 deferred.resolve(devices);
156 }, function fail(response) { 158 }, function fail(response) {
@@ -159,10 +161,11 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -159,10 +161,11 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
159 return deferred.promise; 161 return deferred.promise;
160 } 162 }
161 163
162 - function saveDevice(device) { 164 + function saveDevice(device, config) {
  165 + config = config || {};
163 var deferred = $q.defer(); 166 var deferred = $q.defer();
164 var url = '/api/device'; 167 var url = '/api/device';
165 - $http.post(url, device).then(function success(response) { 168 + $http.post(url, device, config).then(function success(response) {
166 deferred.resolve(response.data); 169 deferred.resolve(response.data);
167 }, function fail() { 170 }, function fail() {
168 deferred.reject(); 171 deferred.reject();
@@ -170,6 +173,54 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -170,6 +173,54 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
170 return deferred.promise; 173 return deferred.promise;
171 } 174 }
172 175
  176 + function saveDeviceRelarion(deviceId, deviceRelation, config) {
  177 + var deferred = $q.defer();
  178 + var attributesType = Object.keys(types.attributesScope);
  179 + var allPromise = [];
  180 + var promise = "";
  181 + for (var i = 0; i < attributesType.length; i++) {
  182 + if (deviceRelation.attributes[attributesType[i]] && deviceRelation.attributes[attributesType[i]].length !== 0) {
  183 + promise = attributeService.saveEntityAttributes(types.entityType.device, deviceId, types.attributesScope[attributesType[i]].value, deviceRelation.attributes[attributesType[i]], config).then(function success() {});
  184 + allPromise.push(promise);
  185 + }
  186 + }
  187 + if (deviceRelation.timeseries.length !== 0) {
  188 + promise = attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config).then(function success() {
  189 + });
  190 + allPromise.push(promise);
  191 + }
  192 + $q.all(allPromise).then(function success() {
  193 + deferred.resolve();
  194 + });
  195 + return deferred.promise;
  196 + }
  197 +
  198 + function saveDeviceParameters(deviceParameters, update, config) {
  199 + config = config || {};
  200 + var deferred = $q.defer();
  201 + var newDevice = {
  202 + name: deviceParameters.name,
  203 + type: deviceParameters.type
  204 + };
  205 + saveDevice(newDevice, config).then(function success(response) {
  206 + saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() {
  207 + deferred.resolve();
  208 + });
  209 + }, function fail() {
  210 + if (update) {
  211 + findByName(deviceParameters.name, config).then(function success(response) {
  212 + saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() {
  213 + deferred.resolve();
  214 + });
  215 + });
  216 + } else {
  217 + deferred.resolve();
  218 + }
  219 + console.log("error"); // eslint-disable-line
  220 + });
  221 + return deferred.promise;
  222 + }
  223 +
173 function deleteDevice(deviceId) { 224 function deleteDevice(deviceId) {
174 var deferred = $q.defer(); 225 var deferred = $q.defer();
175 var url = '/api/device/' + deviceId; 226 var url = '/api/device/' + deviceId;
@@ -297,7 +348,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -297,7 +348,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
297 if (!config) { 348 if (!config) {
298 config = {}; 349 config = {};
299 } 350 }
300 - config = Object.assign(config, { ignoreErrors: ignoreErrors }); 351 + config = Object.assign(config, {ignoreErrors: ignoreErrors});
301 $http.post(url, query, config).then(function success(response) { 352 $http.post(url, query, config).then(function success(response) {
302 deferred.resolve(response.data); 353 deferred.resolve(response.data);
303 }, function fail() { 354 }, function fail() {
@@ -317,4 +368,15 @@ function DeviceService($http, $q, $window, userService, attributeService, custom @@ -317,4 +368,15 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
317 return deferred.promise; 368 return deferred.promise;
318 } 369 }
319 370
  371 + function findByName(deviceName, config) {
  372 + config = config || {};
  373 + var deferred = $q.defer();
  374 + var url = '/api/tenant/devices?deviceName=' + deviceName;
  375 + $http.get(url, config).then(function success(response) {
  376 + deferred.resolve(response.data);
  377 + }, function fail() {
  378 + deferred.reject();
  379 + });
  380 + return deferred.promise;
  381 + }
320 } 382 }
@@ -350,6 +350,40 @@ export default angular.module('thingsboard.types', []) @@ -350,6 +350,40 @@ export default angular.module('thingsboard.types', [])
350 rulenode: "RULE_NODE", 350 rulenode: "RULE_NODE",
351 entityView: "ENTITY_VIEW" 351 entityView: "ENTITY_VIEW"
352 }, 352 },
  353 + entityGroup: {
  354 + columnType: {
  355 + sharedAttribute: {
  356 + name: 'entity-group.column-type.shared-attribute',
  357 + value: 'SHARED_ATTRIBUTE'
  358 + },
  359 + serverAttribute: {
  360 + name: 'entity-group.column-type.server-attribute',
  361 + value: 'SERVER_ATTRIBUTE'
  362 + },
  363 + timeseries: {
  364 + name: 'entity-group.column-type.timeseries',
  365 + value: 'TIMESERIES'
  366 + },
  367 + entityField: {
  368 + name: 'entity-group.column-type.entity-field',
  369 + value: 'ENTITY_FIELD'
  370 + }
  371 + },
  372 + entityField: {
  373 + name: {
  374 + name: 'entity-group.entity-field.name',
  375 + value: 'name'
  376 + },
  377 + type: {
  378 + name: 'entity-group.entity-field.type',
  379 + value: 'type'
  380 + },
  381 + assigned_customer: {
  382 + name: 'entity-group.entity-field.assigned_customer',
  383 + value: 'assigned_customer'
  384 + }
  385 + }
  386 + },
353 aliasEntityType: { 387 aliasEntityType: {
354 current_customer: "CURRENT_CUSTOMER" 388 current_customer: "CURRENT_CUSTOMER"
355 }, 389 },
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 import './import-dialog.scss'; 16 import './import-dialog.scss';
17 17
18 /*@ngInject*/ 18 /*@ngInject*/
19 -export default function ImportDialogCsvController($scope, $mdDialog, toast, importTitle, importFileLabel) { 19 +export default function ImportDialogCsvController($scope, $mdDialog, toast, importTitle, importFileLabel, importExport, types, $timeout) {
20 20
21 var vm = this; 21 var vm = this;
22 22
@@ -25,9 +25,58 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo @@ -25,9 +25,58 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
25 vm.fileAdded = fileAdded; 25 vm.fileAdded = fileAdded;
26 vm.clearFile = clearFile; 26 vm.clearFile = clearFile;
27 27
  28 + vm.addDevices = addDevices;
  29 + vm.importParams = {
  30 + isUpdate: true
  31 + };
  32 +
28 vm.importTitle = importTitle; 33 vm.importTitle = importTitle;
29 vm.importFileLabel = importFileLabel; 34 vm.importFileLabel = importFileLabel;
30 35
  36 + vm.columnsParam = [];
  37 +
  38 + vm.entityType = types.entityType.device;
  39 + vm.columnTypes = {};
  40 + vm.entityField = {};
  41 +
  42 + var parseData = {};
  43 +
  44 + switch (vm.entityType) {
  45 + case types.entityType.device:
  46 + vm.columnTypes = types.entityGroup.columnType;
  47 + break;
  48 + }
  49 +
  50 + vm.entityField.name = types.entityGroup.entityField.name;
  51 +
  52 + switch (vm.entityType) {
  53 + case types.entityType.device:
  54 + vm.entityField.type = types.entityGroup.entityField.type;
  55 + // vm.entityField.assigned_customer = types.entityGroup.entityField.assigned_customer;
  56 + break;
  57 + }
  58 +
  59 + $scope.$watch('vm.columnsParam', function(newVal, prevVal){
  60 + if (newVal && !angular.equals(newVal, prevVal)) {
  61 + var isSelectName = false;
  62 + var isSelectType = false;
  63 + for (var i = 0; i < newVal.length; i++) {
  64 + if (newVal[i].type === types.entityGroup.columnType.entityField.value &&
  65 + newVal[i].key === types.entityGroup.entityField.name.value) {
  66 + isSelectName = true;
  67 + }
  68 + if (newVal[i].type === types.entityGroup.columnType.entityField.value &&
  69 + newVal[i].key === types.entityGroup.entityField.type.value) {
  70 + isSelectType = true;
  71 + }
  72 + }
  73 + $timeout(function () {
  74 + vm.entityField.name.disable = isSelectName;
  75 + vm.entityField.type.disable = isSelectType;
  76 + });
  77 + }
  78 + }, true);
  79 +
31 80
32 function cancel() { 81 function cancel() {
33 $mdDialog.cancel(); 82 $mdDialog.cancel();
@@ -36,16 +85,16 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo @@ -36,16 +85,16 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
36 function fileAdded($file) { 85 function fileAdded($file) {
37 if ($file.getExtension() === 'csv') { 86 if ($file.getExtension() === 'csv') {
38 var reader = new FileReader(); 87 var reader = new FileReader();
39 - reader.onload = function(event) {  
40 - $scope.$apply(function() { 88 + reader.onload = function (event) {
  89 + $scope.$apply(function () {
41 if (event.target.result) { 90 if (event.target.result) {
42 $scope.theForm.$setDirty(); 91 $scope.theForm.$setDirty();
43 var importCSV = event.target.result; 92 var importCSV = event.target.result;
44 if (importCSV && importCSV.length > 0) { 93 if (importCSV && importCSV.length > 0) {
45 try { 94 try {
46 vm.importData = importCSV; 95 vm.importData = importCSV;
47 - console.log(vm.importData); // eslint-disable-line  
48 vm.fileName = $file.name; 96 vm.fileName = $file.name;
  97 + parseCSVData(vm.importData);
49 } catch (err) { 98 } catch (err) {
50 vm.fileName = null; 99 vm.fileName = null;
51 toast.showError(err.message); 100 toast.showError(err.message);
@@ -58,10 +107,89 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo @@ -58,10 +107,89 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
58 } 107 }
59 } 108 }
60 109
  110 + function parseCSVData(importData) {
  111 + var config = {
  112 + delim: vm.importParams.delim,
  113 + header: vm.importParams.isHeader
  114 + };
  115 + parseData = importExport.convertCSVToJson(importData, config);
  116 + for (var i = 0; i < parseData.headers.length; i++) {
  117 + var columnParam = {
  118 + type: types.entityGroup.columnType.serverAttribute.value,
  119 + key: vm.importParams.isHeader ? parseData.headers[i] : "",
  120 + sampleData: parseData.rows[0][i]
  121 + };
  122 + vm.columnsParam.push(columnParam);
  123 + }
  124 + }
  125 +
  126 + function addDevices () {
  127 + var arrayParam = [{type: "ENTITY_FIELD", key: "name", sampleData: "Device 1"}, {type: "ENTITY_FIELD", key: "type", sampleData: "test"}, {type: "SERVER_ATTRIBUTE", key: "test", sampleData: "test"}, {type: "TIMESERIES", key: "testBoolean", sampleData: false}, {type: "SHARED_ATTRIBUTE", key: "testNumber", sampleData: 123}]; // eslint-disable-line
  128 + var data = {headers: ["Device 1", "test", "test", "FALSE", "123"],
  129 + rows:[["Device 1", "test", "test", false, 123.5]]};
  130 + // rows:[["Device 1", "test", "test", false, 123],
  131 + // ["Device 2", "test", "test", false, 124],
  132 + // ["Device 3", "test", "test", false, 125],
  133 + // ["Device 4", "test", "test", false, 126],
  134 + // ["Device 5", "test", "test", false, 127]]};
  135 + var arrayData = [];
  136 + var config = {
  137 + ignoreErrors: true
  138 + };
  139 + for (var i = 0; i < data.rows.length; i ++) {
  140 + var obj = {
  141 + name: "",
  142 + type: "",
  143 + attributes: {
  144 + server: [],
  145 + shared: []
  146 + },
  147 + timeseries: []
  148 + };
  149 + for(var j = 0; j < arrayParam.length; j++){
  150 + switch (arrayParam[j].type) {
  151 + case types.entityGroup.columnType.serverAttribute.value:
  152 + obj.attributes.server.push({
  153 + key: arrayParam[j].key,
  154 + value: data.rows[i][j]
  155 + });
  156 + break;
  157 + case types.entityGroup.columnType.sharedAttribute.value:
  158 + obj.attributes.shared.push({
  159 + key: arrayParam[j].key,
  160 + value: data.rows[i][j]
  161 + });
  162 + break;
  163 + case types.entityGroup.columnType.timeseries.value:
  164 + obj.timeseries.push({
  165 + key: arrayParam[j].key,
  166 + value: data.rows[i][j]
  167 + });
  168 + break;
  169 + case types.entityGroup.columnType.entityField.value:
  170 + switch (arrayParam[j].key) {
  171 + case types.entityGroup.entityField.name.value:
  172 + obj.name = data.rows[i][j];
  173 + break;
  174 + case types.entityGroup.entityField.type.value:
  175 + obj.type = data.rows[i][j];
  176 + break;
  177 + }
  178 + break;
  179 + }
  180 + }
  181 + arrayData.push(obj);
  182 + }
  183 + importExport.createMultiEntity(arrayData, vm.entityType, vm.importParams.isUpdate, config).then(function () {
  184 + $mdDialog.hide();
  185 + });
  186 + }
  187 +
61 function clearFile() { 188 function clearFile() {
62 $scope.theForm.$setDirty(); 189 $scope.theForm.$setDirty();
63 vm.fileName = null; 190 vm.fileName = null;
64 vm.importData = null; 191 vm.importData = null;
  192 + vm.columnsParam = [];
65 } 193 }
66 194
67 function importFromJson() { 195 function importFromJson() {
@@ -26,7 +26,8 @@ @@ -26,7 +26,8 @@
26 </md-button> 26 </md-button>
27 </div> 27 </div>
28 </md-toolbar> 28 </md-toolbar>
29 - <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading" ng-show="$root.loading"></md-progress-linear> 29 + <md-progress-linear class="md-warn" md-mode="indeterminate" ng-disabled="!$root.loading"
  30 + ng-show="$root.loading"></md-progress-linear>
30 <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span> 31 <span style="min-height: 5px;" flex="" ng-show="!$root.loading"></span>
31 <md-dialog-content> 32 <md-dialog-content>
32 <div class="md-dialog-content"> 33 <div class="md-dialog-content">
@@ -38,7 +39,8 @@ @@ -38,7 +39,8 @@
38 flow-file-added="vm.fileAdded( $file )" class="tb-file-select-container"> 39 flow-file-added="vm.fileAdded( $file )" class="tb-file-select-container">
39 <div class="tb-file-clear-container"> 40 <div class="tb-file-clear-container">
40 <md-button ng-click="vm.clearFile()" 41 <md-button ng-click="vm.clearFile()"
41 - class="tb-file-clear-btn md-icon-button md-primary" aria-label="{{ 'action.remove' | translate }}"> 42 + class="tb-file-clear-btn md-icon-button md-primary"
  43 + aria-label="{{ 'action.remove' | translate }}">
42 <md-tooltip md-direction="top"> 44 <md-tooltip md-direction="top">
43 {{ 'action.remove' | translate }} 45 {{ 'action.remove' | translate }}
44 </md-tooltip> 46 </md-tooltip>
@@ -49,7 +51,8 @@ @@ -49,7 +51,8 @@
49 </div> 51 </div>
50 <div class="alert tb-flow-drop" flow-drop> 52 <div class="alert tb-flow-drop" flow-drop>
51 <label for="select" translate>import.drop-file-csv</label> 53 <label for="select" translate>import.drop-file-csv</label>
52 - <input class="file-input" flow-btn flow-attrs="{accept:'.csv,application/csv,text/csv'}" id="select"> 54 + <input class="file-input" flow-btn
  55 + flow-attrs="{accept:'.csv,application/csv,text/csv'}" id="select">
53 </div> 56 </div>
54 </div> 57 </div>
55 </div> 58 </div>
@@ -59,14 +62,81 @@ @@ -59,14 +62,81 @@
59 </div> 62 </div>
60 </div> 63 </div>
61 </fieldset> 64 </fieldset>
  65 + <div flex layout="row">
  66 + <md-input-container class="md-block">
  67 + <label translate>CSV delimiter parametr</label>
  68 + <input ng-model="vm.importParams.delim">
  69 + </md-input-container>
  70 + <md-input-container class="md-block">
  71 + <md-checkbox ng-model="vm.importParams.isHeader" aria-label="Checkbox 1">
  72 + Use first line is header
  73 + </md-checkbox>
  74 + </md-input-container>
  75 + <md-input-container class="md-block">
  76 + <md-checkbox ng-model="vm.importParams.isUpdate" aria-label="Checkbox 1">
  77 + Update parameter device
  78 + </md-checkbox>
  79 + </md-input-container>
  80 + </div>
  81 + <md-table-container flex class="tb-table-select">
  82 + <table md-table>
  83 + <thead md-head>
  84 + <tr md-row>
  85 + <th md-column>&nbsp</th>
  86 + <th md-column>Example value data</th>
  87 + <th md-column style="min-width: 140px">Column type</th>
  88 + <th md-column style="min-width: 140px">Value</th>
  89 + </tr>
  90 + </thead>
  91 + <tbody md-body>
  92 + <tr md-row ng-repeat="column in vm.columnsParam">
  93 + <td md-cell>{{$index + 1}}</td>
  94 + <td md-cell>{{column.sampleData}}</td>
  95 + <td md-cell>
  96 + <md-select ng-model="column.type" required name="columnType"
  97 + aria-label="{{ 'entity-group.column-type' | translate }}">
  98 + <md-option ng-repeat="type in vm.columnTypes" ng-value="type.value">
  99 + {{type.name | translate}}
  100 + </md-option>
  101 + </md-select>
  102 + </td>
  103 + <td md-cell>
  104 + <md-select ng-if="column.type == vm.columnTypes.entityField.value"
  105 + required name="columnKey" ng-model="column.key"
  106 + aria-label="{{ 'entity-group.column-value' | translate }}">
  107 + <md-option ng-repeat="field in vm.entityField" ng-value="field.value" ng-disabled="field.disable">
  108 + {{field.name | translate}}
  109 + </md-option>
  110 + </md-select>
  111 + <md-input-container md-no-float
  112 + ng-if="column.type != vm.columnTypes.entityField.value &&
  113 + column.type != vm.columnTypes.name.value &&
  114 + column.type != vm.columnTypes.type.value">
  115 + <input required name="columnKeyName"
  116 + placeholder="{{ 'entity-group.column-value' | translate }}"
  117 + ng-model="column.key"
  118 + aria-label="{{ 'entity-group.column-value' | translate }}">
  119 + </md-input-container>
  120 + </td>
  121 + </tr>
  122 + </tbody>
  123 + </table>
  124 + <md-divider></md-divider>
  125 + </md-table-container>
62 </div> 126 </div>
63 </md-dialog-content> 127 </md-dialog-content>
64 <md-dialog-actions layout="row"> 128 <md-dialog-actions layout="row">
65 <span flex></span> 129 <span flex></span>
66 - <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid || !vm.importData" type="submit" class="md-raised md-primary"> 130 + <md-button ng-disabled="$root.loading" ng-click="vm.addDevices()" style="margin-right:20px;">
  131 + Add Device
  132 + </md-button>
  133 + <md-button ng-disabled="$root.loading || !theForm.$dirty || !theForm.$valid || !vm.importData" type="submit"
  134 + class="md-raised md-primary">
67 {{ 'action.import' | translate }} 135 {{ 'action.import' | translate }}
68 </md-button> 136 </md-button>
69 - <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel' | translate }}</md-button> 137 + <md-button ng-disabled="$root.loading" ng-click="vm.cancel()" style="margin-right:20px;">{{ 'action.cancel'
  138 + | translate }}
  139 + </md-button>
70 </md-dialog-actions> 140 </md-dialog-actions>
71 </form> 141 </form>
72 </md-dialog> 142 </md-dialog>
@@ -40,3 +40,13 @@ $previewSize: 100px !default; @@ -40,3 +40,13 @@ $previewSize: 100px !default;
40 top: 50%; 40 top: 50%;
41 transform: translate(0%, -50%) !important; 41 transform: translate(0%, -50%) !important;
42 } 42 }
  43 +
  44 +.tb-table-select{
  45 + md-input-container{
  46 + margin: 0;
  47 +
  48 + .md-errors-spacer{
  49 + min-height: 0;
  50 + }
  51 + }
  52 +}
@@ -25,7 +25,7 @@ import entityAliasesTemplate from '../entity/alias/entity-aliases.tpl.html'; @@ -25,7 +25,7 @@ import entityAliasesTemplate from '../entity/alias/entity-aliases.tpl.html';
25 /* eslint-disable no-undef, angular/window-service, angular/document-service */ 25 /* eslint-disable no-undef, angular/window-service, angular/document-service */
26 26
27 /*@ngInject*/ 27 /*@ngInject*/
28 -export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types, 28 +export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types, $timeout, deviceService,
29 dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) { 29 dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) {
30 30
31 31
@@ -43,7 +43,9 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -43,7 +43,9 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
43 exportExtension: exportExtension, 43 exportExtension: exportExtension,
44 importExtension: importExtension, 44 importExtension: importExtension,
45 importDevices: importDevices, 45 importDevices: importDevices,
46 - exportToPc: exportToPc 46 + convertCSVToJson: convertCSVToJson,
  47 + exportToPc: exportToPc,
  48 + createMultiEntity: createMultiEntity
47 }; 49 };
48 50
49 return service; 51 return service;
@@ -56,11 +58,11 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -56,11 +58,11 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
56 var bundleAlias = widgetsBundle.alias; 58 var bundleAlias = widgetsBundle.alias;
57 var isSystem = widgetsBundle.tenantId.id === types.id.nullUid; 59 var isSystem = widgetsBundle.tenantId.id === types.id.nullUid;
58 widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then( 60 widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then(
59 - function success (widgetTypes) { 61 + function success(widgetTypes) {
60 prepareExport(widgetsBundle); 62 prepareExport(widgetsBundle);
61 var widgetsBundleItem = { 63 var widgetsBundleItem = {
62 - widgetsBundle: prepareExport(widgetsBundle),  
63 - widgetTypes: [] 64 + widgetsBundle: prepareExport(widgetsBundle),
  65 + widgetTypes: []
64 }; 66 };
65 for (var t in widgetTypes) { 67 for (var t in widgetTypes) {
66 var widgetType = widgetTypes[t]; 68 var widgetType = widgetTypes[t];
@@ -70,10 +72,10 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -70,10 +72,10 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
70 widgetsBundleItem.widgetTypes.push(prepareExport(widgetType)); 72 widgetsBundleItem.widgetTypes.push(prepareExport(widgetType));
71 } 73 }
72 var name = widgetsBundle.title; 74 var name = widgetsBundle.title;
73 - name = name.toLowerCase().replace(/\W/g,"_"); 75 + name = name.toLowerCase().replace(/\W/g, "_");
74 exportToPc(widgetsBundleItem, name + '.json'); 76 exportToPc(widgetsBundleItem, name + '.json');
75 }, 77 },
76 - function fail (rejection) { 78 + function fail(rejection) {
77 var message = rejection; 79 var message = rejection;
78 if (!message) { 80 if (!message) {
79 message = $translate.instant('error.unknown-error'); 81 message = $translate.instant('error.unknown-error');
@@ -170,7 +172,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -170,7 +172,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
170 delete widgetType.bundleAlias; 172 delete widgetType.bundleAlias;
171 } 173 }
172 var name = widgetType.name; 174 var name = widgetType.name;
173 - name = name.toLowerCase().replace(/\W/g,"_"); 175 + name = name.toLowerCase().replace(/\W/g, "_");
174 exportToPc(prepareExport(widgetType), name + '.json'); 176 exportToPc(prepareExport(widgetType), name + '.json');
175 }, 177 },
176 function fail(rejection) { 178 function fail(rejection) {
@@ -211,8 +213,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -211,8 +213,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
211 213
212 function validateImportedWidgetType(widgetType) { 214 function validateImportedWidgetType(widgetType) {
213 if (angular.isUndefined(widgetType.name) 215 if (angular.isUndefined(widgetType.name)
214 - || angular.isUndefined(widgetType.descriptor))  
215 - { 216 + || angular.isUndefined(widgetType.descriptor)) {
216 return false; 217 return false;
217 } 218 }
218 return true; 219 return true;
@@ -230,7 +231,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -230,7 +231,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
230 metadata: prepareRuleChainMetaData(ruleChainMetaData) 231 metadata: prepareRuleChainMetaData(ruleChainMetaData)
231 }; 232 };
232 var name = ruleChain.name; 233 var name = ruleChain.name;
233 - name = name.toLowerCase().replace(/\W/g,"_"); 234 + name = name.toLowerCase().replace(/\W/g, "_");
234 exportToPc(ruleChainExport, name + '.json'); 235 exportToPc(ruleChainExport, name + '.json');
235 }, 236 },
236 (rejection) => { 237 (rejection) => {
@@ -255,7 +256,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -255,7 +256,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
255 256
256 function prepareRuleChainMetaData(ruleChainMetaData) { 257 function prepareRuleChainMetaData(ruleChainMetaData) {
257 delete ruleChainMetaData.ruleChainId; 258 delete ruleChainMetaData.ruleChainId;
258 - for (var i=0;i<ruleChainMetaData.nodes.length;i++) { 259 + for (var i = 0; i < ruleChainMetaData.nodes.length; i++) {
259 var node = ruleChainMetaData.nodes[i]; 260 var node = ruleChainMetaData.nodes[i];
260 delete node.ruleChainId; 261 delete node.ruleChainId;
261 ruleChainMetaData.nodes[i] = prepareExport(node); 262 ruleChainMetaData.nodes[i] = prepareExport(node);
@@ -307,7 +308,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -307,7 +308,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
307 function exportWidget(dashboard, sourceState, sourceLayout, widget) { 308 function exportWidget(dashboard, sourceState, sourceLayout, widget) {
308 var widgetItem = itembuffer.prepareWidgetItem(dashboard, sourceState, sourceLayout, widget); 309 var widgetItem = itembuffer.prepareWidgetItem(dashboard, sourceState, sourceLayout, widget);
309 var name = widgetItem.widget.config.title; 310 var name = widgetItem.widget.config.title;
310 - name = name.toLowerCase().replace(/\W/g,"_"); 311 + name = name.toLowerCase().replace(/\W/g, "_");
311 exportToPc(prepareExport(widgetItem), name + '.json'); 312 exportToPc(prepareExport(widgetItem), name + '.json');
312 } 313 }
313 314
@@ -417,10 +418,10 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -417,10 +418,10 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
417 var aliasIds = Object.keys(entityAliases); 418 var aliasIds = Object.keys(entityAliases);
418 if (aliasIds.length > 0) { 419 if (aliasIds.length > 0) {
419 processEntityAliases(entityAliases, aliasIds).then( 420 processEntityAliases(entityAliases, aliasIds).then(
420 - function(missingEntityAliases) { 421 + function (missingEntityAliases) {
421 if (Object.keys(missingEntityAliases).length > 0) { 422 if (Object.keys(missingEntityAliases).length > 0) {
422 - editMissingAliases($event, [ widget ],  
423 - true, 'dashboard.widget-import-missing-aliases-title', missingEntityAliases).then( 423 + editMissingAliases($event, [widget],
  424 + true, 'dashboard.widget-import-missing-aliases-title', missingEntityAliases).then(
424 function success(updatedEntityAliases) { 425 function success(updatedEntityAliases) {
425 for (var aliasId in updatedEntityAliases) { 426 for (var aliasId in updatedEntityAliases) {
426 var entityAlias = updatedEntityAliases[aliasId]; 427 var entityAlias = updatedEntityAliases[aliasId];
@@ -485,14 +486,14 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -485,14 +486,14 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
485 function success(targetLayout) { 486 function success(targetLayout) {
486 itembuffer.addWidgetToDashboard(dashboard, targetState, targetLayout, widget, 487 itembuffer.addWidgetToDashboard(dashboard, targetState, targetLayout, widget,
487 aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, -1, -1).then( 488 aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, -1, -1).then(
488 - function() {  
489 - deferred.resolve(  
490 - {  
491 - widget: widget,  
492 - layoutId: targetLayout  
493 - }  
494 - );  
495 - } 489 + function () {
  490 + deferred.resolve(
  491 + {
  492 + widget: widget,
  493 + layoutId: targetLayout
  494 + }
  495 + );
  496 + }
496 ); 497 );
497 }, 498 },
498 function fail() { 499 function fail() {
@@ -507,7 +508,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -507,7 +508,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
507 dashboardService.getDashboard(dashboardId).then( 508 dashboardService.getDashboard(dashboardId).then(
508 function success(dashboard) { 509 function success(dashboard) {
509 var name = dashboard.title; 510 var name = dashboard.title;
510 - name = name.toLowerCase().replace(/\W/g,"_"); 511 + name = name.toLowerCase().replace(/\W/g, "_");
511 exportToPc(prepareDashboardExport(dashboard), name + '.json'); 512 exportToPc(prepareDashboardExport(dashboard), name + '.json');
512 }, 513 },
513 function fail(rejection) { 514 function fail(rejection) {
@@ -540,13 +541,13 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -540,13 +541,13 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
540 dashboard = dashboardUtils.validateAndUpdateDashboard(dashboard); 541 dashboard = dashboardUtils.validateAndUpdateDashboard(dashboard);
541 var entityAliases = dashboard.configuration.entityAliases; 542 var entityAliases = dashboard.configuration.entityAliases;
542 if (entityAliases) { 543 if (entityAliases) {
543 - var aliasIds = Object.keys( entityAliases ); 544 + var aliasIds = Object.keys(entityAliases);
544 if (aliasIds.length > 0) { 545 if (aliasIds.length > 0) {
545 processEntityAliases(entityAliases, aliasIds).then( 546 processEntityAliases(entityAliases, aliasIds).then(
546 - function(missingEntityAliases) {  
547 - if (Object.keys( missingEntityAliases ).length > 0) { 547 + function (missingEntityAliases) {
  548 + if (Object.keys(missingEntityAliases).length > 0) {
548 editMissingAliases($event, dashboard.configuration.widgets, 549 editMissingAliases($event, dashboard.configuration.widgets,
549 - false, 'dashboard.dashboard-import-missing-aliases-title', missingEntityAliases).then( 550 + false, 'dashboard.dashboard-import-missing-aliases-title', missingEntityAliases).then(
550 function success(updatedEntityAliases) { 551 function success(updatedEntityAliases) {
551 for (var aliasId in updatedEntityAliases) { 552 for (var aliasId in updatedEntityAliases) {
552 entityAliases[aliasId] = updatedEntityAliases[aliasId]; 553 entityAliases[aliasId] = updatedEntityAliases[aliasId];
@@ -617,6 +618,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -617,6 +618,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
617 // saveImportedDashboard(dashboard, deferred); 618 // saveImportedDashboard(dashboard, deferred);
618 // } 619 // }
619 // } 620 // }
  621 + deferred.resolve();
620 }, 622 },
621 function fail() { 623 function fail() {
622 deferred.reject(); 624 deferred.reject();
@@ -644,14 +646,13 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -644,14 +646,13 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
644 } 646 }
645 647
646 648
647 -  
648 function exportExtension(extensionId) { 649 function exportExtension(extensionId) {
649 650
650 getExtension(extensionId) 651 getExtension(extensionId)
651 .then( 652 .then(
652 function success(extension) { 653 function success(extension) {
653 var name = extension.title; 654 var name = extension.title;
654 - name = name.toLowerCase().replace(/\W/g,"_"); 655 + name = name.toLowerCase().replace(/\W/g, "_");
655 exportToPc(prepareExport(extension), name + '.json'); 656 exportToPc(prepareExport(extension), name + '.json');
656 }, 657 },
657 function fail(rejection) { 658 function fail(rejection) {
@@ -711,7 +712,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -711,7 +712,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
711 function validateImportedExtension(configuration) { 712 function validateImportedExtension(configuration) {
712 if (configuration.length) { 713 if (configuration.length) {
713 for (let i = 0; i < configuration.length; i++) { 714 for (let i = 0; i < configuration.length; i++) {
714 - if (angular.isUndefined(configuration[i].configuration) || angular.isUndefined(configuration[i].id )|| angular.isUndefined(configuration[i].type)) { 715 + if (angular.isUndefined(configuration[i].configuration) || angular.isUndefined(configuration[i].id) || angular.isUndefined(configuration[i].type)) {
715 return false; 716 return false;
716 } 717 }
717 } 718 }
@@ -742,7 +743,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -742,7 +743,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
742 var aliasId = aliasIds[index]; 743 var aliasId = aliasIds[index];
743 var entityAlias = entityAliases[aliasId]; 744 var entityAlias = entityAliases[aliasId];
744 entityService.checkEntityAlias(entityAlias).then( 745 entityService.checkEntityAlias(entityAlias).then(
745 - function(result) { 746 + function (result) {
746 if (result) { 747 if (result) {
747 checkNextEntityAliasOrComplete(index, aliasIds, entityAliases, missingEntityAliases, deferred); 748 checkNextEntityAliasOrComplete(index, aliasIds, entityAliases, missingEntityAliases, deferred);
748 } else { 749 } else {
@@ -782,6 +783,91 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -782,6 +783,91 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
782 return deferred.promise; 783 return deferred.promise;
783 } 784 }
784 785
  786 + /**
  787 + * splitCSV function (c) 2009 Brian Huisman, see http://www.greywyvern.com/?post=258
  788 + * Works by spliting on seperators first, then patching together quoted values
  789 + */
  790 + function splitCSV(str, sep) {
  791 + for (var foo = str.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) {
  792 + if (foo[x].replace(/"\s+$/, '"').charAt(foo[x].length - 1) == '"') {
  793 + if ((tl = foo[x].replace(/^\s+"/, '"')).length > 1 && tl.charAt(0) == '"') {
  794 + foo[x] = foo[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
  795 + } else if (x) {
  796 + foo.splice(x - 1, 2, [foo[x - 1], foo[x]].join(sep));
  797 + } else foo = foo.shift().split(sep).concat(foo);
  798 + } else foo[x].replace(/""/g, '"');
  799 + }
  800 + return foo;
  801 + }
  802 +
  803 + function isNumeric(str) {
  804 + str = str.replace(',', '.');
  805 + return !isNaN(parseFloat(str)) && isFinite(str);
  806 + }
  807 +
  808 + function parseStringToFormatJS(str) {
  809 + if (isNumeric(str.replace(',', '.'))) {
  810 + return parseFloat(str.replace(',', '.'));
  811 + }
  812 + if (str.search(/^(true|false)$/im) === 0) {
  813 + return str.toLowerCase() === 'true';
  814 + }
  815 + if (str === "") {
  816 + return null;
  817 + }
  818 + return str;
  819 + }
  820 +
  821 + function convertCSVToJson(csvdata, config) {
  822 + config = config || {};
  823 + const delim = config.delim || ",";
  824 + const header = config.header || false;
  825 +
  826 + let csvlines = csvdata.split(/[\r\n]+/);
  827 + let csvheaders = splitCSV(csvlines[0], delim);
  828 + let csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines;
  829 +
  830 + let result = {};
  831 + result.headers = csvheaders;
  832 + result.rows = [];
  833 +
  834 + for (let r in csvrows) {
  835 + if (csvrows.hasOwnProperty(r)) {
  836 + let row = csvrows[r];
  837 +
  838 + if (row.length === 0)
  839 + break;
  840 +
  841 + let rowitems = splitCSV(row, delim);
  842 + for (let i = 0; i < rowitems.length; i++) {
  843 + rowitems[i] = parseStringToFormatJS(rowitems[i]);
  844 + }
  845 + result.rows.push(rowitems);
  846 + }
  847 + }
  848 + return result;
  849 + }
  850 +
  851 + function createMultiEntity(arrayData, entityType, update, config) {
  852 + var deferred = $q.defer();
  853 + var allPromise = [];
  854 + switch (entityType) {
  855 + case types.entityType.device:
  856 + for(var i = 0; i < arrayData.length; i++){
  857 + var promise = deviceService.saveDeviceParameters(arrayData[i], update, config);
  858 + allPromise.push(promise);
  859 + }
  860 + break;
  861 + }
  862 + $q.all(allPromise).then(function success() {
  863 + deferred.resolve();
  864 + $timeout(function () {
  865 + console.log("1"); // eslint-disable-line
  866 + }, 1000);
  867 + });
  868 + return deferred.promise;
  869 + }
  870 +
785 // Common functions 871 // Common functions
786 872
787 function prepareExport(data) { 873 function prepareExport(data) {
@@ -821,8 +907,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -821,8 +907,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
821 907
822 if (window.navigator && window.navigator.msSaveOrOpenBlob) { 908 if (window.navigator && window.navigator.msSaveOrOpenBlob) {
823 window.navigator.msSaveOrOpenBlob(blob, filename); 909 window.navigator.msSaveOrOpenBlob(blob, filename);
824 - }  
825 - else{ 910 + } else {
826 var e = document.createEvent('MouseEvents'), 911 var e = document.createEvent('MouseEvents'),
827 a = document.createElement('a'); 912 a = document.createElement('a');
828 913
@@ -873,7 +958,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, @@ -873,7 +958,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
873 targetEvent: $event 958 targetEvent: $event
874 }).then(function (importData) { 959 }).then(function (importData) {
875 deferred.resolve(importData); 960 deferred.resolve(importData);
876 -  
877 }, function () { 961 }, function () {
878 deferred.reject(); 962 deferred.reject();
879 }); 963 });
@@ -778,6 +778,22 @@ @@ -778,6 +778,22 @@
778 "no-data": "No data to display", 778 "no-data": "No data to display",
779 "columns-to-display": "Columns to Display" 779 "columns-to-display": "Columns to Display"
780 }, 780 },
  781 + "entity-group": {
  782 + "column-value": "Value",
  783 + "column-title": "Title",
  784 + "column-type": {
  785 + "column-type": "Column type",
  786 + "shared-attribute": "Shared attribute",
  787 + "server-attribute": "Server attribute",
  788 + "timeseries": "Timeseries",
  789 + "entity-field": "Entity field"
  790 + },
  791 + "entity-field": {
  792 + "name": "Name",
  793 + "type": "Type",
  794 + "assigned_customer": "Assigned Customer"
  795 + }
  796 + },
781 "entity-view": { 797 "entity-view": {
782 "entity-view": "Entity View", 798 "entity-view": "Entity View",
783 "entity-view-required": "Entity view is required.", 799 "entity-view-required": "Entity view is required.",