Browse Source

Fix dashboard device button, clear code and counted all statistical info

pull/1776/head
Vladyslav_Prykhodko 7 years ago
parent
commit
07cd8b9978
  1. 32
      ui/src/app/api/attribute.service.js
  2. 61
      ui/src/app/api/device.service.js
  3. 4
      ui/src/app/common/types.constant.js
  4. 5
      ui/src/app/device/device.controller.js
  5. 118
      ui/src/app/import-export/import-dialog-csv.controller.js
  6. 60
      ui/src/app/import-export/import-dialog-csv.tpl.html
  7. 52
      ui/src/app/import-export/import-export.service.js
  8. 2
      ui/src/app/import-export/index.js
  9. 91
      ui/src/app/import-export/table-columns-assignment.directive.js
  10. 62
      ui/src/app/import-export/table-columns-assignment.tpl.html
  11. 5
      ui/src/app/locale/locale.constant-en_US.json

32
ui/src/app/api/attribute.service.js

@ -238,23 +238,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
function success() { function success() {
deferred.resolve(response.data); deferred.resolve(response.data);
}, },
function fail(response) { function fail() {
deferred.reject(response); deferred.reject();
} }
) )
} else { } else {
deferred.resolve(response.data); deferred.resolve(response.data);
} }
}, function fail(response) { }, function fail() {
deferred.reject(response); deferred.reject();
}); });
} else if (deleteEntityAttributesPromise) { } else if (deleteEntityAttributesPromise) {
deleteEntityAttributesPromise.then( deleteEntityAttributesPromise.then(
function success() { function success() {
deferred.resolve(); deferred.resolve();
}, },
function fail(response) { function fail() {
deferred.reject(response); deferred.reject();
} }
) )
} else { } else {
@ -287,23 +287,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
function success() { function success() {
deferred.resolve(response.data); deferred.resolve(response.data);
}, },
function fail(response) { function fail() {
deferred.reject(response); deferred.reject();
} }
) )
} else { } else {
deferred.resolve(response.data); deferred.resolve(response.data);
} }
}, function fail(response) { }, function fail() {
deferred.reject(response); deferred.reject();
}); });
} else if (deleteEntityTimeseriesPromise) { } else if (deleteEntityTimeseriesPromise) {
deleteEntityTimeseriesPromise.then( deleteEntityTimeseriesPromise.then(
function success() { function success() {
deferred.resolve(); deferred.resolve();
}, },
function fail(response) { function fail() {
deferred.reject(response); deferred.reject();
} }
) )
} else { } else {
@ -325,8 +325,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys; var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys;
$http.delete(url, config).then(function success() { $http.delete(url, config).then(function success() {
deferred.resolve(); deferred.resolve();
}, function fail(response) { }, function fail() {
deferred.reject(response); deferred.reject();
}); });
return deferred.promise; return deferred.promise;
} }
@ -344,8 +344,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService)
var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys; var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys;
$http.delete(url, config).then(function success() { $http.delete(url, config).then(function success() {
deferred.resolve(); deferred.resolve();
}, function fail(response) { }, function fail() {
deferred.reject(response); deferred.reject();
}); });
return deferred.promise; return deferred.promise;
} }

61
ui/src/app/api/device.service.js

@ -43,8 +43,7 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
sendOneWayRpcCommand: sendOneWayRpcCommand, sendOneWayRpcCommand: sendOneWayRpcCommand,
sendTwoWayRpcCommand: sendTwoWayRpcCommand, sendTwoWayRpcCommand: sendTwoWayRpcCommand,
findByQuery: findByQuery, findByQuery: findByQuery,
getDeviceTypes: getDeviceTypes, getDeviceTypes: getDeviceTypes
findByName: findByName
} }
return service; return service;
@ -167,8 +166,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
var url = '/api/device'; var url = '/api/device';
$http.post(url, device, config).then(function success(response) { $http.post(url, device, config).then(function success(response) {
deferred.resolve(response.data); deferred.resolve(response.data);
}, function fail(response) { }, function fail() {
deferred.reject(response); deferred.reject();
}); });
return deferred.promise; return deferred.promise;
} }
@ -178,18 +177,36 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
let attributesType = Object.keys(types.attributesScope); let attributesType = Object.keys(types.attributesScope);
let allPromise = []; let allPromise = [];
let promise = ""; let promise = "";
let statisticalInfo = {};
for (let i = 0; i < attributesType.length; i++) { for (let i = 0; i < attributesType.length; i++) {
if (deviceRelation.attributes[attributesType[i]] && deviceRelation.attributes[attributesType[i]].length !== 0) { let attrribute = attributesType[i];
promise = attributeService.saveEntityAttributes(types.entityType.device, deviceId, types.attributesScope[attributesType[i]].value, deviceRelation.attributes[attributesType[i]], config); if (deviceRelation.attributes[attrribute] && deviceRelation.attributes[attrribute].length !== 0) {
promise = attributeService.saveEntityAttributes(types.entityType.device, deviceId, types.attributesScope[attrribute].value, deviceRelation.attributes[attrribute], config).then(function () {
statisticalInfo.create = {
[attrribute]: deviceRelation.attributes[attributesType[i]].length
};
}, function () {
statisticalInfo.error = {
[attrribute]: deviceRelation.attributes[attributesType[i]].length
};
});
allPromise.push(promise); allPromise.push(promise);
} }
} }
if (deviceRelation.timeseries.length !== 0) { if (deviceRelation.timeseries.length !== 0) {
promise = attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config); promise = attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config).then(function () {
statisticalInfo.create = {
timeseries: deviceRelation.timeseries.length
};
}, function () {
statisticalInfo.error = {
timeseries: deviceRelation.timeseries.length
};
});
allPromise.push(promise); allPromise.push(promise);
} }
$q.all(allPromise).then(function success() { $q.all(allPromise).then(function success() {
deferred.resolve(); deferred.resolve(statisticalInfo);
}); });
return deferred.promise; return deferred.promise;
} }
@ -197,26 +214,28 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
function saveDeviceParameters(deviceParameters, update, config) { function saveDeviceParameters(deviceParameters, update, config) {
config = config || {}; config = config || {};
const deferred = $q.defer(); const deferred = $q.defer();
let statisticalInfo = { let statisticalInfo = {};
create: {},
update: {},
error: {}
};
let newDevice = { let newDevice = {
name: deviceParameters.name, name: deviceParameters.name,
type: deviceParameters.type type: deviceParameters.type
}; };
saveDevice(newDevice, config).then(function success(response) { saveDevice(newDevice, config).then(function success(response) {
statisticalInfo.create.device = 1; statisticalInfo.create={
saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() { device: 1
};
saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success(response) {
angular.merge(statisticalInfo, response, statisticalInfo);
deferred.resolve(statisticalInfo); deferred.resolve(statisticalInfo);
}); });
}, function fail(response) { }, function fail() {
console.log(response); // eslint-disable-line
if (update) { if (update) {
findByName(deviceParameters.name, config).then(function success(response) { findByName(deviceParameters.name, config).then(function success(response) {
statisticalInfo.update.device = 1; statisticalInfo.update = {
saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() { device: 1
};
saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success(response) {
delete Object.assign(response, {update: response.create}).create;
angular.merge(statisticalInfo, response);
deferred.resolve(statisticalInfo); deferred.resolve(statisticalInfo);
}); });
}, function fail() { }, function fail() {
@ -384,8 +403,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom
var url = '/api/tenant/devices?deviceName=' + deviceName; var url = '/api/tenant/devices?deviceName=' + deviceName;
$http.get(url, config).then(function success(response) { $http.get(url, config).then(function success(response) {
deferred.resolve(response.data); deferred.resolve(response.data);
}, function fail(response) { }, function fail() {
deferred.reject(response); deferred.reject();
}); });
return deferred.promise; return deferred.promise;
} }

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

@ -352,6 +352,10 @@ export default angular.module('thingsboard.types', [])
}, },
entityGroup: { entityGroup: {
columnType: { columnType: {
clientAttribute: {
name: 'entity-group.column-type.client-attribute',
value: 'CLIENT_ATTRIBUTE'
},
sharedAttribute: { sharedAttribute: {
name: 'entity-group.column-type.shared-attribute', name: 'entity-group.column-type.shared-attribute',
value: 'SHARED_ATTRIBUTE' value: 'SHARED_ATTRIBUTE'

5
ui/src/app/device/device.controller.js

@ -68,7 +68,7 @@ export function DeviceController($rootScope, userService, deviceService, custome
}, },
{ {
onAction: function ($event) { onAction: function ($event) {
importExport.importDevices($event).then( importExport.importDevices($event, types.entityType.device).then(
function() { function() {
vm.grid.refreshList(); vm.grid.refreshList();
} }
@ -107,7 +107,6 @@ export function DeviceController($rootScope, userService, deviceService, custome
addItemTemplateUrl: addDeviceTemplate, addItemTemplateUrl: addDeviceTemplate,
// addItemText: function() { return $translate.instant('device.add-device-text') },
noItemsText: function() { return $translate.instant('device.no-devices-text') }, noItemsText: function() { return $translate.instant('device.no-devices-text') },
itemDetailsText: function() { return $translate.instant('device.device-details') }, itemDetailsText: function() { return $translate.instant('device.device-details') },
isDetailsReadOnly: isCustomerUser, isDetailsReadOnly: isCustomerUser,
@ -338,6 +337,7 @@ export function DeviceController($rootScope, userService, deviceService, custome
icon: "add" icon: "add"
}; };
vm.deviceGridConfig.addItemActions = [];
} else if (vm.devicesScope === 'customer_user') { } else if (vm.devicesScope === 'customer_user') {
deviceActionsList.push( deviceActionsList.push(
@ -352,6 +352,7 @@ export function DeviceController($rootScope, userService, deviceService, custome
); );
vm.deviceGridConfig.addItemAction = {}; vm.deviceGridConfig.addItemAction = {};
vm.deviceGridConfig.addItemActions = [];
} }
} }

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

@ -16,7 +16,7 @@
import './import-dialog.scss'; import './import-dialog.scss';
/*@ngInject*/ /*@ngInject*/
export default function ImportDialogCsvController($scope, $mdDialog, toast, importTitle, importFileLabel, importExport, types, $timeout) { export default function ImportDialogCsvController($scope, $mdDialog, toast, importTitle, importFileLabel, entityType, importExport, types, $timeout, $q) {
var vm = this; var vm = this;
@ -27,63 +27,80 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
vm.addDevices = addDevices; vm.addDevices = addDevices;
vm.importParams = { vm.importParams = {
delim: ',',
isUpdate: true, isUpdate: true,
isHeader: true isHeader: true
}; };
vm.selectedStep = 0;
vm.stepProgress = 1;
vm.maxStep = 3;
vm.showBusyText = false;
vm.stepData = [
{ step: 1, completed: false, optional: false, data: {} },
{ step: 2, completed: false, optional: false, data: {} },
{ step: 3, completed: false, optional: false, data: {} },
];
vm.enableNextStep = function nextStep() {
//do not exceed into max step
if (vm.selectedStep >= vm.maxStep) {
return;
}
//do not increment vm.stepProgress when submitting from previously completed step
if (vm.selectedStep === vm.stepProgress - 1) {
vm.stepProgress = vm.stepProgress + 1;
}
vm.selectedStep = vm.selectedStep + 1;
};
vm.moveToPreviousStep = function moveToPreviousStep() {
if (vm.selectedStep > 0) {
vm.selectedStep = vm.selectedStep - 1;
}
};
vm.submitCurrentStep = function submitCurrentStep(stepData, isSkip) {
var deferred = $q.defer();
vm.showBusyText = true;
if (!stepData.completed && !isSkip) {
//simulate $http
$timeout(function () {
vm.showBusyText = false;
deferred.resolve({ status: 200, statusText: 'success', data: {} });
//move to next step when success
stepData.completed = true;
vm.enableNextStep();
}, 1000)
} else {
vm.showBusyText = false;
vm.enableNextStep();
}
};
vm.importTitle = importTitle; vm.importTitle = importTitle;
vm.importFileLabel = importFileLabel; vm.importFileLabel = importFileLabel;
vm.entityType = entityType;
vm.columnsParam = []; vm.columnsParam = [];
vm.parseData = []; vm.parseData = [];
vm.entityType = types.entityType.device; vm.delimiters = [{
vm.columnTypes = {}; key: ',',
vm.entityField = {}; value: ','
},{
key: ';',
value: ';'
},{
key: '|',
value: '|'
},{
key: '\t',
value: 'Tab'
}];
var parseData = {}; var parseData = {};
switch (vm.entityType) {
case types.entityType.device:
vm.columnTypes = types.entityGroup.columnType;
break;
}
vm.entityField.name = types.entityGroup.entityField.name;
switch (vm.entityType) {
case types.entityType.device:
vm.entityField.type = types.entityGroup.entityField.type;
// vm.entityField.assigned_customer = types.entityGroup.entityField.assigned_customer;
break;
}
$scope.$watch('vm.columnsParam', function(newVal, prevVal){
if (newVal && !angular.equals(newVal, prevVal)) {
var isSelectName = false;
var isSelectType = false;
for (var i = 0; i < newVal.length; i++) {
if (newVal[i].type === types.entityGroup.columnType.entityField.value &&
newVal[i].key === types.entityGroup.entityField.name.value) {
isSelectName = true;
}
if (newVal[i].type === types.entityGroup.columnType.entityField.value &&
newVal[i].key === types.entityGroup.entityField.type.value) {
isSelectType = true;
}
}
$timeout(function () {
vm.entityField.name.disable = isSelectName;
vm.entityField.type.disable = isSelectType;
});
}
}, true);
function cancel() {
$mdDialog.cancel();
}
function fileAdded($file) { function fileAdded($file) {
if ($file.getExtension() === 'csv') { if ($file.getExtension() === 'csv') {
var reader = new FileReader(); var reader = new FileReader();
@ -94,9 +111,8 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
var importCSV = event.target.result; var importCSV = event.target.result;
if (importCSV && importCSV.length > 0) { if (importCSV && importCSV.length > 0) {
try { try {
vm.importData = importCSV; parseCSV(importCSV);
vm.fileName = $file.name; vm.fileName = $file.name;
parseCSVData(vm.importData);
} catch (err) { } catch (err) {
vm.fileName = null; vm.fileName = null;
toast.showError(err.message); toast.showError(err.message);
@ -109,7 +125,7 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
} }
} }
function parseCSVData(importData) { function parseCSV(importData) {
var columnParam = {}; var columnParam = {};
var config = { var config = {
delim: vm.importParams.delim, delim: vm.importParams.delim,
@ -202,10 +218,14 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo
function clearFile() { function clearFile() {
$scope.theForm.$setDirty(); $scope.theForm.$setDirty();
vm.fileName = null; vm.fileName = null;
vm.importData = null; parseData = null;
vm.columnsParam = []; vm.columnsParam = [];
} }
function cancel() {
$mdDialog.cancel();
}
function importFromJson() { function importFromJson() {
$scope.theForm.$setPristine(); $scope.theForm.$setPristine();
$mdDialog.hide(vm.importData); $mdDialog.hide(vm.importData);

60
ui/src/app/import-export/import-dialog-csv.tpl.html

@ -63,66 +63,26 @@
</div> </div>
</fieldset> </fieldset>
<div flex layout="row"> <div flex layout="row">
<md-input-container class="md-block"> <md-input-container class="md-block" style="min-width: 120px">
<label translate>CSV delimiter parametr</label> <label translate>CSV delimiter</label>
<input ng-model="vm.importParams.delim"> <md-select ng-model="vm.importParams.delim">
<md-option ng-repeat="delimiter in vm.delimiters" ng-value="delimiter.key">
{{delimiter.value}}
</md-option>
</md-select>
</md-input-container> </md-input-container>
<md-input-container class="md-block"> <md-input-container class="md-block">
<md-checkbox ng-model="vm.importParams.isHeader" aria-label="Checkbox 1"> <md-checkbox ng-model="vm.importParams.isHeader" aria-label="Checkbox 1">
Use first line is header First line is header
</md-checkbox> </md-checkbox>
</md-input-container> </md-input-container>
<md-input-container class="md-block"> <md-input-container class="md-block">
<md-checkbox ng-model="vm.importParams.isUpdate" aria-label="Checkbox 1"> <md-checkbox ng-model="vm.importParams.isUpdate" aria-label="Checkbox 1">
Update parameter device Update parameters
</md-checkbox> </md-checkbox>
</md-input-container> </md-input-container>
</div> </div>
<md-table-container flex class="tb-table-select"> <tb-table-columns-assignment the-form="theForm" columns="vm.columnsParam" entityType="vm.entityType"></tb-table-columns-assignment>
<table md-table>
<thead md-head>
<tr md-row>
<th md-column>&nbsp</th>
<th md-column>Example value data</th>
<th md-column style="min-width: 140px">Column type</th>
<th md-column style="min-width: 140px">Value</th>
</tr>
</thead>
<tbody md-body>
<tr md-row ng-repeat="column in vm.columnsParam">
<td md-cell>{{$index + 1}}</td>
<td md-cell>{{column.sampleData}}</td>
<td md-cell>
<md-select ng-model="column.type" required name="columnType"
aria-label="{{ 'entity-group.column-type' | translate }}">
<md-option ng-repeat="type in vm.columnTypes" ng-value="type.value">
{{type.name | translate}}
</md-option>
</md-select>
</td>
<td md-cell>
<md-select ng-if="column.type == vm.columnTypes.entityField.value"
required name="columnKey" ng-model="column.key"
aria-label="{{ 'entity-group.column-value' | translate }}">
<md-option ng-repeat="field in vm.entityField" ng-value="field.value" ng-disabled="field.disable">
{{field.name | translate}}
</md-option>
</md-select>
<md-input-container md-no-float
ng-if="column.type != vm.columnTypes.entityField.value &&
column.type != vm.columnTypes.name.value &&
column.type != vm.columnTypes.type.value">
<input required name="columnKeyName"
placeholder="{{ 'entity-group.column-value' | translate }}"
ng-model="column.key"
aria-label="{{ 'entity-group.column-value' | translate }}">
</md-input-container>
</td>
</tr>
</tbody>
</table>
<md-divider></md-divider>
</md-table-container>
</div> </div>
</md-dialog-content> </md-dialog-content>
<md-dialog-actions layout="row"> <md-dialog-actions layout="row">

52
ui/src/app/import-export/import-export.service.js

@ -578,9 +578,9 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
return deferred.promise; return deferred.promise;
} }
function importDevices($event) { function importDevices($event, entityType) {
var deferred = $q.defer(); var deferred = $q.defer();
openImportDialogCSV($event, 'device.import', 'device.device-file').then( openImportDialogCSV($event, entityType,'device.import', 'device.device-file').then(
function success() { function success() {
// if (!validateImportedDashboard(dashboard)) { // if (!validateImportedDashboard(dashboard)) {
// toast.showError($translate.instant('dashboard.invalid-dashboard-file-error')); // toast.showError($translate.instant('dashboard.invalid-dashboard-file-error'));
@ -783,10 +783,6 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
return deferred.promise; return deferred.promise;
} }
/**
* splitCSV function (c) 2009 Brian Huisman, see http://www.greywyvern.com/?post=258
* Works by spliting on seperators first, then patching together quoted values
*/
function splitCSV(str, sep) { function splitCSV(str, sep) {
for (var foo = str.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) { for (var foo = str.split(sep = sep || ","), x = foo.length - 1, tl; x >= 0; x--) {
if (foo[x].replace(/"\s+$/, '"').charAt(foo[x].length - 1) == '"') { if (foo[x].replace(/"\s+$/, '"').charAt(foo[x].length - 1) == '"') {
@ -805,7 +801,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
return !isNaN(parseFloat(str)) && isFinite(str); return !isNaN(parseFloat(str)) && isFinite(str);
} }
function parseStringToFormatJS(str) { function convertStringToJSType(str) {
if (isNumeric(str.replace(',', '.'))) { if (isNumeric(str.replace(',', '.'))) {
return parseFloat(str.replace(',', '.')); return parseFloat(str.replace(',', '.'));
} }
@ -827,7 +823,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
let csvlines = csvdata.split(/[\r\n]+/); let csvlines = csvdata.split(/[\r\n]+/);
let csvheaders = splitCSV(csvlines[0], delim); let csvheaders = splitCSV(csvlines[0], delim);
if (csvheaders.length < 2) { if (csvheaders.length < 2) {
toast.showError('A file should contain at least two columns'); toast.showError($translate.instant('entity.import-csv-number-columns-error'));
return -1; return -1;
} }
let csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines; let csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines;
@ -844,34 +840,47 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
let rowitems = splitCSV(row, delim); let rowitems = splitCSV(row, delim);
if (rowitems.length !== result.headers.length) { if (rowitems.length !== result.headers.length) {
toast.showError('Invalid file format. Row:' + (header ? result.rows.length + 2: result.rows.length + 1)); toast.showError($translate.instant('entity.import-csv-invalid-format-error', {line: (header ? result.rows.length + 2: result.rows.length + 1)}));
return -1; return -1;
} }
for (let i = 0; i < rowitems.length; i++) { for (let i = 0; i < rowitems.length; i++) {
rowitems[i] = parseStringToFormatJS(rowitems[i]); rowitems[i] = convertStringToJSType(rowitems[i]);
} }
result.rows.push(rowitems); result.rows.push(rowitems);
} }
} }
return result; return result;
} }
function sumObject(obj1, obj2){
Object.keys(obj2).map(function(key) {
if (angular.isObject(obj2[key])) {
obj1[key] = obj1[key] || {};
angular.merge(obj1[key], sumObject(obj1[key], obj2[key]));
} else {
obj1[key] = (obj1[key] || 0) + obj2[key];
}
});
return obj1;
}
function createMultiEntity(arrayData, entityType, update, config) { function createMultiEntity(arrayData, entityType, update, config) {
var deferred = $q.defer(); let deferred = $q.defer();
var allPromise = []; let allPromise = [];
let statisticalInfo = {};
switch (entityType) { switch (entityType) {
case types.entityType.device: case types.entityType.device:
for(var i = 0; i < arrayData.length; i++){ for(let i = 0; i < arrayData.length; i++){
var promise = deviceService.saveDeviceParameters(arrayData[i], update, config); const promise = deviceService.saveDeviceParameters(arrayData[i], update, config);
allPromise.push(promise); allPromise.push(promise);
} }
break; break;
} }
$q.all(allPromise).then(function success() { $q.all(allPromise).then(function success(response) {
deferred.resolve(); for (let i = 0; i < response.length; i++){
$timeout(function () { statisticalInfo = sumObject(statisticalInfo, response[i]);
console.log("1"); // eslint-disable-line }
}, 1000); deferred.resolve(statisticalInfo);
}); });
return deferred.promise; return deferred.promise;
} }
@ -950,7 +959,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
return deferred.promise; return deferred.promise;
} }
function openImportDialogCSV($event, importTitle, importFileLabel) { function openImportDialogCSV($event, entityType, importTitle, importFileLabel) {
var deferred = $q.defer(); var deferred = $q.defer();
$mdDialog.show({ $mdDialog.show({
controller: 'ImportDialogCSVController', controller: 'ImportDialogCSVController',
@ -958,7 +967,8 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
templateUrl: importDialogCSVTemplate, templateUrl: importDialogCSVTemplate,
locals: { locals: {
importTitle: importTitle, importTitle: importTitle,
importFileLabel: importFileLabel importFileLabel: importFileLabel,
entityType: entityType
}, },
parent: angular.element($document[0].body), parent: angular.element($document[0].body),
multiple: true, multiple: true,

2
ui/src/app/import-export/index.js

@ -16,10 +16,12 @@
import ImportExport from './import-export.service'; import ImportExport from './import-export.service';
import ImportDialogController from './import-dialog.controller'; import ImportDialogController from './import-dialog.controller';
import ImportDialogCSVController from './import-dialog-csv.controller'; import ImportDialogCSVController from './import-dialog-csv.controller';
import TableColumnsAssignment from './table-columns-assignment.directive';
export default angular.module('thingsboard.importexport', []) export default angular.module('thingsboard.importexport', [])
.factory('importExport', ImportExport) .factory('importExport', ImportExport)
.controller('ImportDialogController', ImportDialogController) .controller('ImportDialogController', ImportDialogController)
.controller('ImportDialogCSVController', ImportDialogCSVController) .controller('ImportDialogCSVController', ImportDialogCSVController)
.directive('tbTableColumnsAssignment', TableColumnsAssignment)
.name; .name;

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

@ -0,0 +1,91 @@
/*
* Copyright © 2016-2019 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// import './timeinterval.scss';
/* eslint-disable import/no-unresolved, import/default */
import tableColumnsAssignment from './table-columns-assignment.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function TableColumnsAssignment() {
return {
restrict: "E",
scope: true,
bindToController: {
theForm: '=?',
columns: '=',
entityType: '=',
},
templateUrl: tableColumnsAssignment,
controller: TableColumnsAssignmentController,
controllerAs: 'vm'
};
}
/*@ngInject*/
function TableColumnsAssignmentController($scope, types, $timeout) {
var vm = this;
vm.columnTypes = {};
vm.entityField = {};
switch (vm.entityType) {
case types.entityType.device:
vm.columnTypes.sharedAttribute = types.entityGroup.columnType.sharedAttribute;
vm.columnTypes.serverAttribute = types.entityGroup.columnType.serverAttribute;
vm.columnTypes.timeseries = types.entityGroup.columnType.timeseries;
vm.columnTypes.entityField = types.entityGroup.columnType.entityField;
break;
}
vm.entityField.name = types.entityGroup.entityField.name;
switch (vm.entityType) {
case types.entityType.device:
vm.entityField.type = types.entityGroup.entityField.type;
// vm.entityField.assigned_customer = types.entityGroup.entityField.assigned_customer;
break;
}
$scope.$watch('vm.columns', function(newVal, prevVal){
if (newVal && !angular.equals(newVal, prevVal)) {
var isSelectName = false;
var isSelectType = false;
for (var i = 0; i < newVal.length; i++) {
if (newVal[i].type === types.entityGroup.columnType.entityField.value &&
newVal[i].key === types.entityGroup.entityField.name.value) {
isSelectName = true;
}
if (newVal[i].type === types.entityGroup.columnType.entityField.value &&
newVal[i].key === types.entityGroup.entityField.type.value) {
isSelectType = true;
}
}
$timeout(function () {
vm.entityField.name.disable = isSelectName;
vm.entityField.type.disable = isSelectType;
});
}
}, true);
$scope.$watch('vm.columns', function(newVal, prevVal) {
if (vm.isEdit && !angular.equals(newVal, prevVal)) {
vm.theForm.$setDirty();
}
}, true);
}

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

@ -0,0 +1,62 @@
<!--
Copyright © 2016-2019 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<md-table-container flex class="tb-table-select">
<table md-table>
<thead md-head>
<tr md-row>
<th md-column>&nbsp</th>
<th md-column>Example value data</th>
<th md-column style="min-width: 140px">Column type</th>
<th md-column style="min-width: 140px">Value</th>
</tr>
</thead>
<tbody md-body>
<tr md-row ng-repeat="column in vm.columns track by $index">
<td md-cell>{{$index + 1}}</td>
<td md-cell>{{column.sampleData}}</td>
<td md-cell>
<md-select ng-model="column.type" required name="columnType"
aria-label="{{ 'entity-group.column-type' | translate }}">
<md-option ng-repeat="type in vm.columnTypes" ng-value="type.value">
{{type.name | translate}}
</md-option>
</md-select>
</td>
<td md-cell>
<md-select ng-if="column.type == vm.columnTypes.entityField.value"
required name="columnKey" ng-model="column.key"
aria-label="{{ 'entity-group.column-value' | translate }}">
<md-option ng-repeat="field in vm.entityField" ng-value="field.value" ng-disabled="field.disable">
{{field.name | translate}}
</md-option>
</md-select>
<md-input-container md-no-float
ng-if="column.type != vm.columnTypes.entityField.value &&
column.type != vm.columnTypes.name.value &&
column.type != vm.columnTypes.type.value">
<input required name="columnKeyName"
placeholder="{{ 'entity-group.column-value' | translate }}"
ng-model="column.key"
aria-label="{{ 'entity-group.column-value' | translate }}">
</md-input-container>
</td>
</tr>
</tbody>
</table>
<md-divider></md-divider>
</md-table-container>

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

@ -776,13 +776,16 @@
"details": "Entity details", "details": "Entity details",
"no-entities-prompt": "No entities found", "no-entities-prompt": "No entities found",
"no-data": "No data to display", "no-data": "No data to display",
"columns-to-display": "Columns to Display" "columns-to-display": "Columns to Display",
"import-csv-number-columns-error": "A file should contain at least two columns",
"import-csv-invalid-format-error": "Invalid file format. Line: '{{line}}'"
}, },
"entity-group": { "entity-group": {
"column-value": "Value", "column-value": "Value",
"column-title": "Title", "column-title": "Title",
"column-type": { "column-type": {
"column-type": "Column type", "column-type": "Column type",
"client-attribute": "Client attribute",
"shared-attribute": "Shared attribute", "shared-attribute": "Shared attribute",
"server-attribute": "Server attribute", "server-attribute": "Server attribute",
"timeseries": "Timeseries", "timeseries": "Timeseries",

Loading…
Cancel
Save