Commit 07cd8b9978b810cd2c0bffcaad453fcab9a09233
1 parent
62f43369
Fix dashboard device button, clear code and counted all statistical info
Showing
11 changed files
with
332 additions
and
160 deletions
@@ -238,23 +238,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | @@ -238,23 +238,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | ||
238 | function success() { | 238 | function success() { |
239 | deferred.resolve(response.data); | 239 | deferred.resolve(response.data); |
240 | }, | 240 | }, |
241 | - function fail(response) { | ||
242 | - deferred.reject(response); | 241 | + function fail() { |
242 | + deferred.reject(); | ||
243 | } | 243 | } |
244 | ) | 244 | ) |
245 | } else { | 245 | } else { |
246 | deferred.resolve(response.data); | 246 | deferred.resolve(response.data); |
247 | } | 247 | } |
248 | - }, function fail(response) { | ||
249 | - deferred.reject(response); | 248 | + }, function fail() { |
249 | + deferred.reject(); | ||
250 | }); | 250 | }); |
251 | } else if (deleteEntityAttributesPromise) { | 251 | } else if (deleteEntityAttributesPromise) { |
252 | deleteEntityAttributesPromise.then( | 252 | deleteEntityAttributesPromise.then( |
253 | function success() { | 253 | function success() { |
254 | deferred.resolve(); | 254 | deferred.resolve(); |
255 | }, | 255 | }, |
256 | - function fail(response) { | ||
257 | - deferred.reject(response); | 256 | + function fail() { |
257 | + deferred.reject(); | ||
258 | } | 258 | } |
259 | ) | 259 | ) |
260 | } else { | 260 | } else { |
@@ -287,23 +287,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | @@ -287,23 +287,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | ||
287 | function success() { | 287 | function success() { |
288 | deferred.resolve(response.data); | 288 | deferred.resolve(response.data); |
289 | }, | 289 | }, |
290 | - function fail(response) { | ||
291 | - deferred.reject(response); | 290 | + function fail() { |
291 | + deferred.reject(); | ||
292 | } | 292 | } |
293 | ) | 293 | ) |
294 | } else { | 294 | } else { |
295 | deferred.resolve(response.data); | 295 | deferred.resolve(response.data); |
296 | } | 296 | } |
297 | - }, function fail(response) { | ||
298 | - deferred.reject(response); | 297 | + }, function fail() { |
298 | + deferred.reject(); | ||
299 | }); | 299 | }); |
300 | } else if (deleteEntityTimeseriesPromise) { | 300 | } else if (deleteEntityTimeseriesPromise) { |
301 | deleteEntityTimeseriesPromise.then( | 301 | deleteEntityTimeseriesPromise.then( |
302 | function success() { | 302 | function success() { |
303 | deferred.resolve(); | 303 | deferred.resolve(); |
304 | }, | 304 | }, |
305 | - function fail(response) { | ||
306 | - deferred.reject(response); | 305 | + function fail() { |
306 | + deferred.reject(); | ||
307 | } | 307 | } |
308 | ) | 308 | ) |
309 | } else { | 309 | } else { |
@@ -325,8 +325,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | @@ -325,8 +325,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | ||
325 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys; | 325 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys; |
326 | $http.delete(url, config).then(function success() { | 326 | $http.delete(url, config).then(function success() { |
327 | deferred.resolve(); | 327 | deferred.resolve(); |
328 | - }, function fail(response) { | ||
329 | - deferred.reject(response); | 328 | + }, function fail() { |
329 | + deferred.reject(); | ||
330 | }); | 330 | }); |
331 | return deferred.promise; | 331 | return deferred.promise; |
332 | } | 332 | } |
@@ -344,8 +344,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | @@ -344,8 +344,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | ||
344 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys; | 344 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys; |
345 | $http.delete(url, config).then(function success() { | 345 | $http.delete(url, config).then(function success() { |
346 | deferred.resolve(); | 346 | deferred.resolve(); |
347 | - }, function fail(response) { | ||
348 | - deferred.reject(response); | 347 | + }, function fail() { |
348 | + deferred.reject(); | ||
349 | }); | 349 | }); |
350 | return deferred.promise; | 350 | return deferred.promise; |
351 | } | 351 | } |
@@ -43,8 +43,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | @@ -43,8 +43,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | ||
43 | sendOneWayRpcCommand: sendOneWayRpcCommand, | 43 | sendOneWayRpcCommand: sendOneWayRpcCommand, |
44 | sendTwoWayRpcCommand: sendTwoWayRpcCommand, | 44 | sendTwoWayRpcCommand: sendTwoWayRpcCommand, |
45 | findByQuery: findByQuery, | 45 | findByQuery: findByQuery, |
46 | - getDeviceTypes: getDeviceTypes, | ||
47 | - findByName: findByName | 46 | + getDeviceTypes: getDeviceTypes |
48 | } | 47 | } |
49 | 48 | ||
50 | return service; | 49 | return service; |
@@ -167,8 +166,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | @@ -167,8 +166,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | ||
167 | var url = '/api/device'; | 166 | var url = '/api/device'; |
168 | $http.post(url, device, config).then(function success(response) { | 167 | $http.post(url, device, config).then(function success(response) { |
169 | deferred.resolve(response.data); | 168 | deferred.resolve(response.data); |
170 | - }, function fail(response) { | ||
171 | - deferred.reject(response); | 169 | + }, function fail() { |
170 | + deferred.reject(); | ||
172 | }); | 171 | }); |
173 | return deferred.promise; | 172 | return deferred.promise; |
174 | } | 173 | } |
@@ -178,18 +177,36 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | @@ -178,18 +177,36 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | ||
178 | let attributesType = Object.keys(types.attributesScope); | 177 | let attributesType = Object.keys(types.attributesScope); |
179 | let allPromise = []; | 178 | let allPromise = []; |
180 | let promise = ""; | 179 | let promise = ""; |
180 | + let statisticalInfo = {}; | ||
181 | for (let i = 0; i < attributesType.length; i++) { | 181 | for (let 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); | 182 | + let attrribute = attributesType[i]; |
183 | + if (deviceRelation.attributes[attrribute] && deviceRelation.attributes[attrribute].length !== 0) { | ||
184 | + promise = attributeService.saveEntityAttributes(types.entityType.device, deviceId, types.attributesScope[attrribute].value, deviceRelation.attributes[attrribute], config).then(function () { | ||
185 | + statisticalInfo.create = { | ||
186 | + [attrribute]: deviceRelation.attributes[attributesType[i]].length | ||
187 | + }; | ||
188 | + }, function () { | ||
189 | + statisticalInfo.error = { | ||
190 | + [attrribute]: deviceRelation.attributes[attributesType[i]].length | ||
191 | + }; | ||
192 | + }); | ||
184 | allPromise.push(promise); | 193 | allPromise.push(promise); |
185 | } | 194 | } |
186 | } | 195 | } |
187 | if (deviceRelation.timeseries.length !== 0) { | 196 | if (deviceRelation.timeseries.length !== 0) { |
188 | - promise = attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config); | 197 | + promise = attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config).then(function () { |
198 | + statisticalInfo.create = { | ||
199 | + timeseries: deviceRelation.timeseries.length | ||
200 | + }; | ||
201 | + }, function () { | ||
202 | + statisticalInfo.error = { | ||
203 | + timeseries: deviceRelation.timeseries.length | ||
204 | + }; | ||
205 | + }); | ||
189 | allPromise.push(promise); | 206 | allPromise.push(promise); |
190 | } | 207 | } |
191 | $q.all(allPromise).then(function success() { | 208 | $q.all(allPromise).then(function success() { |
192 | - deferred.resolve(); | 209 | + deferred.resolve(statisticalInfo); |
193 | }); | 210 | }); |
194 | return deferred.promise; | 211 | return deferred.promise; |
195 | } | 212 | } |
@@ -197,26 +214,28 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | @@ -197,26 +214,28 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | ||
197 | function saveDeviceParameters(deviceParameters, update, config) { | 214 | function saveDeviceParameters(deviceParameters, update, config) { |
198 | config = config || {}; | 215 | config = config || {}; |
199 | const deferred = $q.defer(); | 216 | const deferred = $q.defer(); |
200 | - let statisticalInfo = { | ||
201 | - create: {}, | ||
202 | - update: {}, | ||
203 | - error: {} | ||
204 | - }; | 217 | + let statisticalInfo = {}; |
205 | let newDevice = { | 218 | let newDevice = { |
206 | name: deviceParameters.name, | 219 | name: deviceParameters.name, |
207 | type: deviceParameters.type | 220 | type: deviceParameters.type |
208 | }; | 221 | }; |
209 | saveDevice(newDevice, config).then(function success(response) { | 222 | saveDevice(newDevice, config).then(function success(response) { |
210 | - statisticalInfo.create.device = 1; | ||
211 | - saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() { | 223 | + statisticalInfo.create={ |
224 | + device: 1 | ||
225 | + }; | ||
226 | + saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success(response) { | ||
227 | + angular.merge(statisticalInfo, response, statisticalInfo); | ||
212 | deferred.resolve(statisticalInfo); | 228 | deferred.resolve(statisticalInfo); |
213 | }); | 229 | }); |
214 | - }, function fail(response) { | ||
215 | - console.log(response); // eslint-disable-line | 230 | + }, function fail() { |
216 | if (update) { | 231 | if (update) { |
217 | findByName(deviceParameters.name, config).then(function success(response) { | 232 | findByName(deviceParameters.name, config).then(function success(response) { |
218 | - statisticalInfo.update.device = 1; | ||
219 | - saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() { | 233 | + statisticalInfo.update = { |
234 | + device: 1 | ||
235 | + }; | ||
236 | + saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success(response) { | ||
237 | + delete Object.assign(response, {update: response.create}).create; | ||
238 | + angular.merge(statisticalInfo, response); | ||
220 | deferred.resolve(statisticalInfo); | 239 | deferred.resolve(statisticalInfo); |
221 | }); | 240 | }); |
222 | }, function fail() { | 241 | }, function fail() { |
@@ -384,8 +403,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | @@ -384,8 +403,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom | ||
384 | var url = '/api/tenant/devices?deviceName=' + deviceName; | 403 | var url = '/api/tenant/devices?deviceName=' + deviceName; |
385 | $http.get(url, config).then(function success(response) { | 404 | $http.get(url, config).then(function success(response) { |
386 | deferred.resolve(response.data); | 405 | deferred.resolve(response.data); |
387 | - }, function fail(response) { | ||
388 | - deferred.reject(response); | 406 | + }, function fail() { |
407 | + deferred.reject(); | ||
389 | }); | 408 | }); |
390 | return deferred.promise; | 409 | return deferred.promise; |
391 | } | 410 | } |
@@ -352,6 +352,10 @@ export default angular.module('thingsboard.types', []) | @@ -352,6 +352,10 @@ export default angular.module('thingsboard.types', []) | ||
352 | }, | 352 | }, |
353 | entityGroup: { | 353 | entityGroup: { |
354 | columnType: { | 354 | columnType: { |
355 | + clientAttribute: { | ||
356 | + name: 'entity-group.column-type.client-attribute', | ||
357 | + value: 'CLIENT_ATTRIBUTE' | ||
358 | + }, | ||
355 | sharedAttribute: { | 359 | sharedAttribute: { |
356 | name: 'entity-group.column-type.shared-attribute', | 360 | name: 'entity-group.column-type.shared-attribute', |
357 | value: 'SHARED_ATTRIBUTE' | 361 | value: 'SHARED_ATTRIBUTE' |
@@ -68,7 +68,7 @@ export function DeviceController($rootScope, userService, deviceService, custome | @@ -68,7 +68,7 @@ export function DeviceController($rootScope, userService, deviceService, custome | ||
68 | }, | 68 | }, |
69 | { | 69 | { |
70 | onAction: function ($event) { | 70 | onAction: function ($event) { |
71 | - importExport.importDevices($event).then( | 71 | + importExport.importDevices($event, types.entityType.device).then( |
72 | function() { | 72 | function() { |
73 | vm.grid.refreshList(); | 73 | vm.grid.refreshList(); |
74 | } | 74 | } |
@@ -107,7 +107,6 @@ export function DeviceController($rootScope, userService, deviceService, custome | @@ -107,7 +107,6 @@ export function DeviceController($rootScope, userService, deviceService, custome | ||
107 | 107 | ||
108 | addItemTemplateUrl: addDeviceTemplate, | 108 | addItemTemplateUrl: addDeviceTemplate, |
109 | 109 | ||
110 | - // addItemText: function() { return $translate.instant('device.add-device-text') }, | ||
111 | noItemsText: function() { return $translate.instant('device.no-devices-text') }, | 110 | noItemsText: function() { return $translate.instant('device.no-devices-text') }, |
112 | itemDetailsText: function() { return $translate.instant('device.device-details') }, | 111 | itemDetailsText: function() { return $translate.instant('device.device-details') }, |
113 | isDetailsReadOnly: isCustomerUser, | 112 | isDetailsReadOnly: isCustomerUser, |
@@ -338,6 +337,7 @@ export function DeviceController($rootScope, userService, deviceService, custome | @@ -338,6 +337,7 @@ export function DeviceController($rootScope, userService, deviceService, custome | ||
338 | icon: "add" | 337 | icon: "add" |
339 | }; | 338 | }; |
340 | 339 | ||
340 | + vm.deviceGridConfig.addItemActions = []; | ||
341 | 341 | ||
342 | } else if (vm.devicesScope === 'customer_user') { | 342 | } else if (vm.devicesScope === 'customer_user') { |
343 | deviceActionsList.push( | 343 | deviceActionsList.push( |
@@ -352,6 +352,7 @@ export function DeviceController($rootScope, userService, deviceService, custome | @@ -352,6 +352,7 @@ export function DeviceController($rootScope, userService, deviceService, custome | ||
352 | ); | 352 | ); |
353 | 353 | ||
354 | vm.deviceGridConfig.addItemAction = {}; | 354 | vm.deviceGridConfig.addItemAction = {}; |
355 | + vm.deviceGridConfig.addItemActions = []; | ||
355 | } | 356 | } |
356 | } | 357 | } |
357 | 358 |
@@ -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, importExport, types, $timeout) { | 19 | +export default function ImportDialogCsvController($scope, $mdDialog, toast, importTitle, importFileLabel, entityType, importExport, types, $timeout, $q) { |
20 | 20 | ||
21 | var vm = this; | 21 | var vm = this; |
22 | 22 | ||
@@ -27,63 +27,80 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | @@ -27,63 +27,80 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | ||
27 | 27 | ||
28 | vm.addDevices = addDevices; | 28 | vm.addDevices = addDevices; |
29 | vm.importParams = { | 29 | vm.importParams = { |
30 | + delim: ',', | ||
30 | isUpdate: true, | 31 | isUpdate: true, |
31 | isHeader: true | 32 | isHeader: true |
32 | }; | 33 | }; |
33 | 34 | ||
35 | + vm.selectedStep = 0; | ||
36 | + vm.stepProgress = 1; | ||
37 | + vm.maxStep = 3; | ||
38 | + vm.showBusyText = false; | ||
39 | + vm.stepData = [ | ||
40 | + { step: 1, completed: false, optional: false, data: {} }, | ||
41 | + { step: 2, completed: false, optional: false, data: {} }, | ||
42 | + { step: 3, completed: false, optional: false, data: {} }, | ||
43 | + ]; | ||
44 | + | ||
45 | + vm.enableNextStep = function nextStep() { | ||
46 | + //do not exceed into max step | ||
47 | + if (vm.selectedStep >= vm.maxStep) { | ||
48 | + return; | ||
49 | + } | ||
50 | + //do not increment vm.stepProgress when submitting from previously completed step | ||
51 | + if (vm.selectedStep === vm.stepProgress - 1) { | ||
52 | + vm.stepProgress = vm.stepProgress + 1; | ||
53 | + } | ||
54 | + vm.selectedStep = vm.selectedStep + 1; | ||
55 | + }; | ||
56 | + | ||
57 | + vm.moveToPreviousStep = function moveToPreviousStep() { | ||
58 | + if (vm.selectedStep > 0) { | ||
59 | + vm.selectedStep = vm.selectedStep - 1; | ||
60 | + } | ||
61 | + }; | ||
62 | + | ||
63 | + vm.submitCurrentStep = function submitCurrentStep(stepData, isSkip) { | ||
64 | + var deferred = $q.defer(); | ||
65 | + vm.showBusyText = true; | ||
66 | + if (!stepData.completed && !isSkip) { | ||
67 | + //simulate $http | ||
68 | + $timeout(function () { | ||
69 | + vm.showBusyText = false; | ||
70 | + deferred.resolve({ status: 200, statusText: 'success', data: {} }); | ||
71 | + //move to next step when success | ||
72 | + stepData.completed = true; | ||
73 | + vm.enableNextStep(); | ||
74 | + }, 1000) | ||
75 | + } else { | ||
76 | + vm.showBusyText = false; | ||
77 | + vm.enableNextStep(); | ||
78 | + } | ||
79 | + }; | ||
80 | + | ||
34 | vm.importTitle = importTitle; | 81 | vm.importTitle = importTitle; |
35 | vm.importFileLabel = importFileLabel; | 82 | vm.importFileLabel = importFileLabel; |
83 | + vm.entityType = entityType; | ||
36 | 84 | ||
37 | vm.columnsParam = []; | 85 | vm.columnsParam = []; |
38 | vm.parseData = []; | 86 | vm.parseData = []; |
39 | 87 | ||
40 | - vm.entityType = types.entityType.device; | ||
41 | - vm.columnTypes = {}; | ||
42 | - vm.entityField = {}; | 88 | + vm.delimiters = [{ |
89 | + key: ',', | ||
90 | + value: ',' | ||
91 | + },{ | ||
92 | + key: ';', | ||
93 | + value: ';' | ||
94 | + },{ | ||
95 | + key: '|', | ||
96 | + value: '|' | ||
97 | + },{ | ||
98 | + key: '\t', | ||
99 | + value: 'Tab' | ||
100 | + }]; | ||
43 | 101 | ||
44 | var parseData = {}; | 102 | var parseData = {}; |
45 | 103 | ||
46 | - switch (vm.entityType) { | ||
47 | - case types.entityType.device: | ||
48 | - vm.columnTypes = types.entityGroup.columnType; | ||
49 | - break; | ||
50 | - } | ||
51 | - | ||
52 | - vm.entityField.name = types.entityGroup.entityField.name; | ||
53 | - | ||
54 | - switch (vm.entityType) { | ||
55 | - case types.entityType.device: | ||
56 | - vm.entityField.type = types.entityGroup.entityField.type; | ||
57 | - // vm.entityField.assigned_customer = types.entityGroup.entityField.assigned_customer; | ||
58 | - break; | ||
59 | - } | ||
60 | - | ||
61 | - $scope.$watch('vm.columnsParam', function(newVal, prevVal){ | ||
62 | - if (newVal && !angular.equals(newVal, prevVal)) { | ||
63 | - var isSelectName = false; | ||
64 | - var isSelectType = false; | ||
65 | - for (var i = 0; i < newVal.length; i++) { | ||
66 | - if (newVal[i].type === types.entityGroup.columnType.entityField.value && | ||
67 | - newVal[i].key === types.entityGroup.entityField.name.value) { | ||
68 | - isSelectName = true; | ||
69 | - } | ||
70 | - if (newVal[i].type === types.entityGroup.columnType.entityField.value && | ||
71 | - newVal[i].key === types.entityGroup.entityField.type.value) { | ||
72 | - isSelectType = true; | ||
73 | - } | ||
74 | - } | ||
75 | - $timeout(function () { | ||
76 | - vm.entityField.name.disable = isSelectName; | ||
77 | - vm.entityField.type.disable = isSelectType; | ||
78 | - }); | ||
79 | - } | ||
80 | - }, true); | ||
81 | - | ||
82 | - | ||
83 | - function cancel() { | ||
84 | - $mdDialog.cancel(); | ||
85 | - } | ||
86 | - | ||
87 | function fileAdded($file) { | 104 | function fileAdded($file) { |
88 | if ($file.getExtension() === 'csv') { | 105 | if ($file.getExtension() === 'csv') { |
89 | var reader = new FileReader(); | 106 | var reader = new FileReader(); |
@@ -94,9 +111,8 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | @@ -94,9 +111,8 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | ||
94 | var importCSV = event.target.result; | 111 | var importCSV = event.target.result; |
95 | if (importCSV && importCSV.length > 0) { | 112 | if (importCSV && importCSV.length > 0) { |
96 | try { | 113 | try { |
97 | - vm.importData = importCSV; | 114 | + parseCSV(importCSV); |
98 | vm.fileName = $file.name; | 115 | vm.fileName = $file.name; |
99 | - parseCSVData(vm.importData); | ||
100 | } catch (err) { | 116 | } catch (err) { |
101 | vm.fileName = null; | 117 | vm.fileName = null; |
102 | toast.showError(err.message); | 118 | toast.showError(err.message); |
@@ -109,7 +125,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | @@ -109,7 +125,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | ||
109 | } | 125 | } |
110 | } | 126 | } |
111 | 127 | ||
112 | - function parseCSVData(importData) { | 128 | + function parseCSV(importData) { |
113 | var columnParam = {}; | 129 | var columnParam = {}; |
114 | var config = { | 130 | var config = { |
115 | delim: vm.importParams.delim, | 131 | delim: vm.importParams.delim, |
@@ -202,10 +218,14 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | @@ -202,10 +218,14 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo | ||
202 | function clearFile() { | 218 | function clearFile() { |
203 | $scope.theForm.$setDirty(); | 219 | $scope.theForm.$setDirty(); |
204 | vm.fileName = null; | 220 | vm.fileName = null; |
205 | - vm.importData = null; | 221 | + parseData = null; |
206 | vm.columnsParam = []; | 222 | vm.columnsParam = []; |
207 | } | 223 | } |
208 | 224 | ||
225 | + function cancel() { | ||
226 | + $mdDialog.cancel(); | ||
227 | + } | ||
228 | + | ||
209 | function importFromJson() { | 229 | function importFromJson() { |
210 | $scope.theForm.$setPristine(); | 230 | $scope.theForm.$setPristine(); |
211 | $mdDialog.hide(vm.importData); | 231 | $mdDialog.hide(vm.importData); |
@@ -63,66 +63,26 @@ | @@ -63,66 +63,26 @@ | ||
63 | </div> | 63 | </div> |
64 | </fieldset> | 64 | </fieldset> |
65 | <div flex layout="row"> | 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"> | 66 | + <md-input-container class="md-block" style="min-width: 120px"> |
67 | + <label translate>CSV delimiter</label> | ||
68 | + <md-select ng-model="vm.importParams.delim"> | ||
69 | + <md-option ng-repeat="delimiter in vm.delimiters" ng-value="delimiter.key"> | ||
70 | + {{delimiter.value}} | ||
71 | + </md-option> | ||
72 | + </md-select> | ||
69 | </md-input-container> | 73 | </md-input-container> |
70 | <md-input-container class="md-block"> | 74 | <md-input-container class="md-block"> |
71 | <md-checkbox ng-model="vm.importParams.isHeader" aria-label="Checkbox 1"> | 75 | <md-checkbox ng-model="vm.importParams.isHeader" aria-label="Checkbox 1"> |
72 | - Use first line is header | 76 | + First line is header |
73 | </md-checkbox> | 77 | </md-checkbox> |
74 | </md-input-container> | 78 | </md-input-container> |
75 | <md-input-container class="md-block"> | 79 | <md-input-container class="md-block"> |
76 | <md-checkbox ng-model="vm.importParams.isUpdate" aria-label="Checkbox 1"> | 80 | <md-checkbox ng-model="vm.importParams.isUpdate" aria-label="Checkbox 1"> |
77 | - Update parameter device | 81 | + Update parameters |
78 | </md-checkbox> | 82 | </md-checkbox> |
79 | </md-input-container> | 83 | </md-input-container> |
80 | </div> | 84 | </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> </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> | 85 | + <tb-table-columns-assignment the-form="theForm" columns="vm.columnsParam" entityType="vm.entityType"></tb-table-columns-assignment> |
126 | </div> | 86 | </div> |
127 | </md-dialog-content> | 87 | </md-dialog-content> |
128 | <md-dialog-actions layout="row"> | 88 | <md-dialog-actions layout="row"> |
@@ -578,9 +578,9 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -578,9 +578,9 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
578 | return deferred.promise; | 578 | return deferred.promise; |
579 | } | 579 | } |
580 | 580 | ||
581 | - function importDevices($event) { | 581 | + function importDevices($event, entityType) { |
582 | var deferred = $q.defer(); | 582 | var deferred = $q.defer(); |
583 | - openImportDialogCSV($event, 'device.import', 'device.device-file').then( | 583 | + openImportDialogCSV($event, entityType,'device.import', 'device.device-file').then( |
584 | function success() { | 584 | function success() { |
585 | // if (!validateImportedDashboard(dashboard)) { | 585 | // if (!validateImportedDashboard(dashboard)) { |
586 | // toast.showError($translate.instant('dashboard.invalid-dashboard-file-error')); | 586 | // toast.showError($translate.instant('dashboard.invalid-dashboard-file-error')); |
@@ -783,10 +783,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -783,10 +783,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
783 | return deferred.promise; | 783 | return deferred.promise; |
784 | } | 784 | } |
785 | 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) { | 786 | function splitCSV(str, sep) { |
791 | for (var foo = str.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) { | 787 | 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) == '"') { | 788 | if (foo[x].replace(/"\s+$/, '"').charAt(foo[x].length - 1) == '"') { |
@@ -805,7 +801,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -805,7 +801,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
805 | return !isNaN(parseFloat(str)) && isFinite(str); | 801 | return !isNaN(parseFloat(str)) && isFinite(str); |
806 | } | 802 | } |
807 | 803 | ||
808 | - function parseStringToFormatJS(str) { | 804 | + function convertStringToJSType(str) { |
809 | if (isNumeric(str.replace(',', '.'))) { | 805 | if (isNumeric(str.replace(',', '.'))) { |
810 | return parseFloat(str.replace(',', '.')); | 806 | return parseFloat(str.replace(',', '.')); |
811 | } | 807 | } |
@@ -827,7 +823,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -827,7 +823,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
827 | let csvlines = csvdata.split(/[\r\n]+/); | 823 | let csvlines = csvdata.split(/[\r\n]+/); |
828 | let csvheaders = splitCSV(csvlines[0], delim); | 824 | let csvheaders = splitCSV(csvlines[0], delim); |
829 | if (csvheaders.length < 2) { | 825 | if (csvheaders.length < 2) { |
830 | - toast.showError('A file should contain at least two columns'); | 826 | + toast.showError($translate.instant('entity.import-csv-number-columns-error')); |
831 | return -1; | 827 | return -1; |
832 | } | 828 | } |
833 | let csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines; | 829 | let csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines; |
@@ -844,34 +840,47 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -844,34 +840,47 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
844 | 840 | ||
845 | let rowitems = splitCSV(row, delim); | 841 | let rowitems = splitCSV(row, delim); |
846 | if (rowitems.length !== result.headers.length) { | 842 | if (rowitems.length !== result.headers.length) { |
847 | - toast.showError('Invalid file format. Row:' + (header ? result.rows.length + 2: result.rows.length + 1)); | 843 | + toast.showError($translate.instant('entity.import-csv-invalid-format-error', {line: (header ? result.rows.length + 2: result.rows.length + 1)})); |
848 | return -1; | 844 | return -1; |
849 | } | 845 | } |
850 | for (let i = 0; i < rowitems.length; i++) { | 846 | for (let i = 0; i < rowitems.length; i++) { |
851 | - rowitems[i] = parseStringToFormatJS(rowitems[i]); | 847 | + rowitems[i] = convertStringToJSType(rowitems[i]); |
852 | } | 848 | } |
853 | result.rows.push(rowitems); | 849 | result.rows.push(rowitems); |
854 | } | 850 | } |
855 | } | 851 | } |
856 | return result; | 852 | return result; |
857 | } | 853 | } |
854 | + | ||
855 | + function sumObject(obj1, obj2){ | ||
856 | + Object.keys(obj2).map(function(key) { | ||
857 | + if (angular.isObject(obj2[key])) { | ||
858 | + obj1[key] = obj1[key] || {}; | ||
859 | + angular.merge(obj1[key], sumObject(obj1[key], obj2[key])); | ||
860 | + } else { | ||
861 | + obj1[key] = (obj1[key] || 0) + obj2[key]; | ||
862 | + } | ||
863 | + }); | ||
864 | + return obj1; | ||
865 | + } | ||
858 | 866 | ||
859 | function createMultiEntity(arrayData, entityType, update, config) { | 867 | function createMultiEntity(arrayData, entityType, update, config) { |
860 | - var deferred = $q.defer(); | ||
861 | - var allPromise = []; | 868 | + let deferred = $q.defer(); |
869 | + let allPromise = []; | ||
870 | + let statisticalInfo = {}; | ||
862 | switch (entityType) { | 871 | switch (entityType) { |
863 | case types.entityType.device: | 872 | case types.entityType.device: |
864 | - for(var i = 0; i < arrayData.length; i++){ | ||
865 | - var promise = deviceService.saveDeviceParameters(arrayData[i], update, config); | 873 | + for(let i = 0; i < arrayData.length; i++){ |
874 | + const promise = deviceService.saveDeviceParameters(arrayData[i], update, config); | ||
866 | allPromise.push(promise); | 875 | allPromise.push(promise); |
867 | } | 876 | } |
868 | break; | 877 | break; |
869 | } | 878 | } |
870 | - $q.all(allPromise).then(function success() { | ||
871 | - deferred.resolve(); | ||
872 | - $timeout(function () { | ||
873 | - console.log("1"); // eslint-disable-line | ||
874 | - }, 1000); | 879 | + $q.all(allPromise).then(function success(response) { |
880 | + for (let i = 0; i < response.length; i++){ | ||
881 | + statisticalInfo = sumObject(statisticalInfo, response[i]); | ||
882 | + } | ||
883 | + deferred.resolve(statisticalInfo); | ||
875 | }); | 884 | }); |
876 | return deferred.promise; | 885 | return deferred.promise; |
877 | } | 886 | } |
@@ -950,7 +959,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -950,7 +959,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
950 | return deferred.promise; | 959 | return deferred.promise; |
951 | } | 960 | } |
952 | 961 | ||
953 | - function openImportDialogCSV($event, importTitle, importFileLabel) { | 962 | + function openImportDialogCSV($event, entityType, importTitle, importFileLabel) { |
954 | var deferred = $q.defer(); | 963 | var deferred = $q.defer(); |
955 | $mdDialog.show({ | 964 | $mdDialog.show({ |
956 | controller: 'ImportDialogCSVController', | 965 | controller: 'ImportDialogCSVController', |
@@ -958,7 +967,8 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -958,7 +967,8 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
958 | templateUrl: importDialogCSVTemplate, | 967 | templateUrl: importDialogCSVTemplate, |
959 | locals: { | 968 | locals: { |
960 | importTitle: importTitle, | 969 | importTitle: importTitle, |
961 | - importFileLabel: importFileLabel | 970 | + importFileLabel: importFileLabel, |
971 | + entityType: entityType | ||
962 | }, | 972 | }, |
963 | parent: angular.element($document[0].body), | 973 | parent: angular.element($document[0].body), |
964 | multiple: true, | 974 | multiple: true, |
@@ -16,10 +16,12 @@ | @@ -16,10 +16,12 @@ | ||
16 | import ImportExport from './import-export.service'; | 16 | import ImportExport from './import-export.service'; |
17 | import ImportDialogController from './import-dialog.controller'; | 17 | import ImportDialogController from './import-dialog.controller'; |
18 | import ImportDialogCSVController from './import-dialog-csv.controller'; | 18 | import ImportDialogCSVController from './import-dialog-csv.controller'; |
19 | +import TableColumnsAssignment from './table-columns-assignment.directive'; | ||
19 | 20 | ||
20 | 21 | ||
21 | export default angular.module('thingsboard.importexport', []) | 22 | export default angular.module('thingsboard.importexport', []) |
22 | .factory('importExport', ImportExport) | 23 | .factory('importExport', ImportExport) |
23 | .controller('ImportDialogController', ImportDialogController) | 24 | .controller('ImportDialogController', ImportDialogController) |
24 | .controller('ImportDialogCSVController', ImportDialogCSVController) | 25 | .controller('ImportDialogCSVController', ImportDialogCSVController) |
26 | + .directive('tbTableColumnsAssignment', TableColumnsAssignment) | ||
25 | .name; | 27 | .name; |
1 | +/* | ||
2 | + * Copyright © 2016-2019 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +// import './timeinterval.scss'; | ||
17 | + | ||
18 | +/* eslint-disable import/no-unresolved, import/default */ | ||
19 | + | ||
20 | +import tableColumnsAssignment from './table-columns-assignment.tpl.html'; | ||
21 | + | ||
22 | +/* eslint-enable import/no-unresolved, import/default */ | ||
23 | + | ||
24 | +/*@ngInject*/ | ||
25 | +export default function TableColumnsAssignment() { | ||
26 | + return { | ||
27 | + restrict: "E", | ||
28 | + scope: true, | ||
29 | + bindToController: { | ||
30 | + theForm: '=?', | ||
31 | + columns: '=', | ||
32 | + entityType: '=', | ||
33 | + }, | ||
34 | + templateUrl: tableColumnsAssignment, | ||
35 | + controller: TableColumnsAssignmentController, | ||
36 | + controllerAs: 'vm' | ||
37 | + }; | ||
38 | +} | ||
39 | + | ||
40 | +/*@ngInject*/ | ||
41 | +function TableColumnsAssignmentController($scope, types, $timeout) { | ||
42 | + var vm = this; | ||
43 | + | ||
44 | + vm.columnTypes = {}; | ||
45 | + vm.entityField = {}; | ||
46 | + | ||
47 | + switch (vm.entityType) { | ||
48 | + case types.entityType.device: | ||
49 | + vm.columnTypes.sharedAttribute = types.entityGroup.columnType.sharedAttribute; | ||
50 | + vm.columnTypes.serverAttribute = types.entityGroup.columnType.serverAttribute; | ||
51 | + vm.columnTypes.timeseries = types.entityGroup.columnType.timeseries; | ||
52 | + vm.columnTypes.entityField = types.entityGroup.columnType.entityField; | ||
53 | + break; | ||
54 | + } | ||
55 | + | ||
56 | + vm.entityField.name = types.entityGroup.entityField.name; | ||
57 | + | ||
58 | + switch (vm.entityType) { | ||
59 | + case types.entityType.device: | ||
60 | + vm.entityField.type = types.entityGroup.entityField.type; | ||
61 | + // vm.entityField.assigned_customer = types.entityGroup.entityField.assigned_customer; | ||
62 | + break; | ||
63 | + } | ||
64 | + | ||
65 | + $scope.$watch('vm.columns', function(newVal, prevVal){ | ||
66 | + if (newVal && !angular.equals(newVal, prevVal)) { | ||
67 | + var isSelectName = false; | ||
68 | + var isSelectType = false; | ||
69 | + for (var i = 0; i < newVal.length; i++) { | ||
70 | + if (newVal[i].type === types.entityGroup.columnType.entityField.value && | ||
71 | + newVal[i].key === types.entityGroup.entityField.name.value) { | ||
72 | + isSelectName = true; | ||
73 | + } | ||
74 | + if (newVal[i].type === types.entityGroup.columnType.entityField.value && | ||
75 | + newVal[i].key === types.entityGroup.entityField.type.value) { | ||
76 | + isSelectType = true; | ||
77 | + } | ||
78 | + } | ||
79 | + $timeout(function () { | ||
80 | + vm.entityField.name.disable = isSelectName; | ||
81 | + vm.entityField.type.disable = isSelectType; | ||
82 | + }); | ||
83 | + } | ||
84 | + }, true); | ||
85 | + | ||
86 | + $scope.$watch('vm.columns', function(newVal, prevVal) { | ||
87 | + if (vm.isEdit && !angular.equals(newVal, prevVal)) { | ||
88 | + vm.theForm.$setDirty(); | ||
89 | + } | ||
90 | + }, true); | ||
91 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2019 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<md-table-container flex class="tb-table-select"> | ||
19 | + <table md-table> | ||
20 | + <thead md-head> | ||
21 | + <tr md-row> | ||
22 | + <th md-column> </th> | ||
23 | + <th md-column>Example value data</th> | ||
24 | + <th md-column style="min-width: 140px">Column type</th> | ||
25 | + <th md-column style="min-width: 140px">Value</th> | ||
26 | + </tr> | ||
27 | + </thead> | ||
28 | + <tbody md-body> | ||
29 | + <tr md-row ng-repeat="column in vm.columns track by $index"> | ||
30 | + <td md-cell>{{$index + 1}}</td> | ||
31 | + <td md-cell>{{column.sampleData}}</td> | ||
32 | + <td md-cell> | ||
33 | + <md-select ng-model="column.type" required name="columnType" | ||
34 | + aria-label="{{ 'entity-group.column-type' | translate }}"> | ||
35 | + <md-option ng-repeat="type in vm.columnTypes" ng-value="type.value"> | ||
36 | + {{type.name | translate}} | ||
37 | + </md-option> | ||
38 | + </md-select> | ||
39 | + </td> | ||
40 | + <td md-cell> | ||
41 | + <md-select ng-if="column.type == vm.columnTypes.entityField.value" | ||
42 | + required name="columnKey" ng-model="column.key" | ||
43 | + aria-label="{{ 'entity-group.column-value' | translate }}"> | ||
44 | + <md-option ng-repeat="field in vm.entityField" ng-value="field.value" ng-disabled="field.disable"> | ||
45 | + {{field.name | translate}} | ||
46 | + </md-option> | ||
47 | + </md-select> | ||
48 | + <md-input-container md-no-float | ||
49 | + ng-if="column.type != vm.columnTypes.entityField.value && | ||
50 | + column.type != vm.columnTypes.name.value && | ||
51 | + column.type != vm.columnTypes.type.value"> | ||
52 | + <input required name="columnKeyName" | ||
53 | + placeholder="{{ 'entity-group.column-value' | translate }}" | ||
54 | + ng-model="column.key" | ||
55 | + aria-label="{{ 'entity-group.column-value' | translate }}"> | ||
56 | + </md-input-container> | ||
57 | + </td> | ||
58 | + </tr> | ||
59 | + </tbody> | ||
60 | + </table> | ||
61 | + <md-divider></md-divider> | ||
62 | +</md-table-container> |
@@ -776,13 +776,16 @@ | @@ -776,13 +776,16 @@ | ||
776 | "details": "Entity details", | 776 | "details": "Entity details", |
777 | "no-entities-prompt": "No entities found", | 777 | "no-entities-prompt": "No entities found", |
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 | + "import-csv-number-columns-error": "A file should contain at least two columns", | ||
781 | + "import-csv-invalid-format-error": "Invalid file format. Line: '{{line}}'" | ||
780 | }, | 782 | }, |
781 | "entity-group": { | 783 | "entity-group": { |
782 | "column-value": "Value", | 784 | "column-value": "Value", |
783 | "column-title": "Title", | 785 | "column-title": "Title", |
784 | "column-type": { | 786 | "column-type": { |
785 | "column-type": "Column type", | 787 | "column-type": "Column type", |
788 | + "client-attribute": "Client attribute", | ||
786 | "shared-attribute": "Shared attribute", | 789 | "shared-attribute": "Shared attribute", |
787 | "server-attribute": "Server attribute", | 790 | "server-attribute": "Server attribute", |
788 | "timeseries": "Timeseries", | 791 | "timeseries": "Timeseries", |