Commit f5c80afa537ab37719bcadd4a7406b3572124142

Authored by Sergey Tarnavskiy
2 parents 2583cbed 5795e7f2

add export/import buttons to widget

... ... @@ -70,6 +70,7 @@
70 70 <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.operatingItem().additionalInfo.gateway" md-on-select="vm.grid.triggerResize()" label="{{ 'extension.extensions' | translate }}">
71 71 <tb-extension-table flex
72 72 entity-id="vm.grid.operatingItem().id.id"
  73 + entity-name="vm.grid.operatingItem().name"
73 74 entity-type="{{vm.types.entityType.device}}">
74 75 </tb-extension-table>
75 76 </md-tab>
... ...
... ... @@ -36,7 +36,8 @@ export default function ExtensionTableDirective() {
36 36 entityId: '=',
37 37 entityType: '@',
38 38 inWidget: '@?',
39   - ctx: '=?'
  39 + ctx: '=?',
  40 + entityName: '='
40 41 },
41 42 controller: ExtensionTableController,
42 43 controllerAs: 'vm',
... ... @@ -45,7 +46,7 @@ export default function ExtensionTableDirective() {
45 46 }
46 47
47 48 /*@ngInject*/
48   -function ExtensionTableController($scope, $filter, $document, $translate, types, $mdDialog, attributeService, telemetryWebsocketService) {
  49 +function ExtensionTableController($scope, $filter, $document, $translate, types, $mdDialog, attributeService, telemetryWebsocketService, importExport) {
49 50
50 51 let vm = this;
51 52
... ... @@ -122,6 +123,16 @@ function ExtensionTableController($scope, $filter, $document, $translate, types,
122 123 addExtension();
123 124 }
124 125 });
  126 + $scope.$on("exportExtensions", function($event, source) {
  127 + if(source.entityId == vm.entityId) {
  128 + vm.exportExtensions(source.entityName);
  129 + }
  130 + });
  131 + $scope.$on("importExtensions", function($event, source) {
  132 + if(source.entityId == vm.entityId) {
  133 + vm.importExtensions();
  134 + }
  135 + });
125 136
126 137 function enterFilterMode() {
127 138 vm.query.search = '';
... ... @@ -364,4 +375,23 @@ function ExtensionTableController($scope, $filter, $document, $translate, types,
364 375 return num;
365 376 }
366 377 }
  378 +
  379 + vm.importExtensions = function($event) {
  380 + importExport.importExtension($event, {"entityType":vm.entityType, "entityId":vm.entityId, "successFunc":reloadExtensions});
  381 + };
  382 + vm.exportExtensions = function(widgetSourceEntityName) {
  383 + if(vm.inWidget) {
  384 + importExport.exportToPc(vm.extensionsJSON, widgetSourceEntityName + '_configuration.json');
  385 + } else {
  386 + importExport.exportToPc(vm.extensionsJSON, vm.entityName + '_configuration.json');
  387 + }
  388 + };
  389 +
  390 + /*change function for widget implementing, like vm.exportExtensions*/
  391 + vm.exportExtension = function($event, extension) {
  392 + if ($event) {
  393 + $event.stopPropagation();
  394 + }
  395 + importExport.exportToPc(extension, vm.entityName +'_'+ extension.id +'_configuration.json');
  396 + };
367 397 }
\ No newline at end of file
... ...
... ... @@ -16,11 +16,16 @@
16 16 @import '../../scss/constants';
17 17
18 18
19   -.extension-table md-input-container .md-errors-spacer {
20   - min-height: 0;
21   -}
22   -
23 19 .extension-table {
  20 +
  21 + md-input-container .md-errors-spacer {
  22 + min-height: 0;
  23 + }
  24 +
  25 + /*&.tb-data-table table.md-table tbody tr td.tb-action-cell,
  26 + &.tb-data-table table.md-table.md-row-select tbody tr td.tb-action-cell {
  27 + width: 114px;
  28 + }*/
24 29 .sync-widget {
25 30 max-height: 90px;
26 31 overflow: hidden;
... ... @@ -31,7 +36,6 @@
31 36 }
32 37 }
33 38
34   -
35 39 .extension__syncStatus--black {
36 40 color: #000000!important;
37 41 }
... ...
... ... @@ -23,6 +23,19 @@
23 23 <div class="md-toolbar-tools">
24 24 <span translate>{{ 'extension.extensions' }}</span>
25 25 <span flex></span>
  26 +
  27 + <md-button class="md-icon-button" ng-click="vm.importExtensions($event)">
  28 + <md-icon>file_upload</md-icon>
  29 + <md-tooltip md-direction="top">
  30 + {{ 'extension.import-extensions-configuration' | translate }}
  31 + </md-tooltip>
  32 + </md-button>
  33 + <md-button class="md-icon-button" ng-click="vm.exportExtensions()">
  34 + <md-icon>file_download</md-icon>
  35 + <md-tooltip md-direction="top">
  36 + {{ 'extension.export-extensions-configuration' | translate }}
  37 + </md-tooltip>
  38 + </md-button>
26 39 <md-button class="md-icon-button" ng-click="vm.addExtension($event)">
27 40 <md-icon>add</md-icon>
28 41 <md-tooltip md-direction="top">
... ... @@ -111,6 +124,14 @@
111 124 <td md-cell>{{ extension.id }}</td>
112 125 <td md-cell>{{ extension.type }}</td>
113 126 <td md-cell class="tb-action-cell">
  127 +
  128 + <!--<md-button class="md-icon-button" aria-label="{{ 'action.edit' | translate }}" ng-click="vm.exportExtension($event, extension)">
  129 + <md-icon aria-label="{{ 'action.edit' | translate }}" class="material-icons">file_download</md-icon>
  130 + <md-tooltip md-direction="top">
  131 + {{ 'extension.export-extension' | translate }}
  132 + </md-tooltip>
  133 + </md-button>-->
  134 +
114 135 <md-button class="md-icon-button" aria-label="{{ 'action.edit' | translate }}" ng-click="vm.editExtension($event, extension)">
115 136 <md-icon aria-label="{{ 'action.edit' | translate }}" class="material-icons">edit</md-icon>
116 137 <md-tooltip md-direction="top">
... ...
... ... @@ -24,8 +24,9 @@ import entityAliasesTemplate from '../entity/alias/entity-aliases.tpl.html';
24 24 /* eslint-disable no-undef, angular/window-service, angular/document-service */
25 25
26 26 /*@ngInject*/
27   -export default function ImportExport($log, $translate, $q, $mdDialog, $document, itembuffer, utils, types, dashboardUtils,
28   - entityService, dashboardService, pluginService, ruleService, widgetService, toast) {
  27 +export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types,
  28 + dashboardUtils, entityService, dashboardService, pluginService, ruleService,
  29 + widgetService, toast, attributeService) {
29 30
30 31
31 32 var service = {
... ... @@ -40,8 +41,11 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
40 41 exportWidgetType: exportWidgetType,
41 42 importWidgetType: importWidgetType,
42 43 exportWidgetsBundle: exportWidgetsBundle,
43   - importWidgetsBundle: importWidgetsBundle
44   - }
  44 + importWidgetsBundle: importWidgetsBundle,
  45 + exportExtension: exportExtension,
  46 + importExtension: importExtension,
  47 + exportToPc: exportToPc
  48 + };
45 49
46 50 return service;
47 51
... ... @@ -614,6 +618,84 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
614 618 return true;
615 619 }
616 620
  621 +
  622 +
  623 + function exportExtension(extensionId) {
  624 +
  625 + getExtension(extensionId)
  626 + .then(
  627 + function success(extension) {
  628 + var name = extension.title;
  629 + name = name.toLowerCase().replace(/\W/g,"_");
  630 + exportToPc(prepareExport(extension), name + '.json');
  631 + },
  632 + function fail(rejection) {
  633 + var message = rejection;
  634 + if (!message) {
  635 + message = $translate.instant('error.unknown-error');
  636 + }
  637 + toast.showError($translate.instant('extension.export-failed-error', {error: message}));
  638 + }
  639 + );
  640 +
  641 + function getExtension(extensionId) {
  642 + var deferred = $q.defer();
  643 + var url = '/api/plugins/telemetry/DEVICE/' + extensionId;
  644 + $http.get(url, null)
  645 + .then(function success(response) {
  646 + deferred.resolve(response.data);
  647 + }, function fail() {
  648 + deferred.reject();
  649 + });
  650 + return deferred.promise;
  651 + }
  652 +
  653 + }
  654 +
  655 + function importExtension($event, options) {
  656 + var deferred = $q.defer();
  657 + openImportDialog($event, 'extension.import-extensions', 'extension.file')
  658 + .then(
  659 + function success(extension) {
  660 + if (!validateImportedExtension(extension)) {
  661 + toast.showError($translate.instant('extension.invalid-file-error'));
  662 + deferred.reject();
  663 + } else {
  664 + attributeService
  665 + .saveEntityAttributes(
  666 + options.entityType,
  667 + options.entityId,
  668 + types.attributesScope.shared.value,
  669 + [{
  670 + key: "configuration",
  671 + value: angular.toJson(extension)
  672 + }]
  673 + )
  674 + .then(function success() {
  675 + options.successFunc();
  676 + });
  677 + }
  678 + },
  679 + function fail() {
  680 + deferred.reject();
  681 + }
  682 + );
  683 + return deferred.promise;
  684 + }
  685 +
  686 + function validateImportedExtension(configuration) {
  687 + if (configuration.length) {
  688 + for (let i = 0; i < configuration.length; i++) {
  689 + if (angular.isUndefined(configuration[i].configuration) || angular.isUndefined(configuration[i].id )|| angular.isUndefined(configuration[i].type)) {
  690 + return false;
  691 + }
  692 + }
  693 + } else {
  694 + return false;
  695 + }
  696 + return true;
  697 + }
  698 +
617 699 function processEntityAliases(entityAliases, aliasIds) {
618 700 var deferred = $q.defer();
619 701 var missingEntityAliases = {};
... ...
... ... @@ -847,6 +847,14 @@ export default angular.module('thingsboard.locale', [])
847 847 "last-sync-time": "Last sync time",
848 848 "not-available": "Not available"
849 849 },
  850 +
  851 + "export-extensions-configuration":"Export extensions configuration",
  852 + "import-extensions-configuration":"Import extensions configuration",
  853 + "import-extensions": "Import extensions",
  854 + "import-extension": "Import extension",
  855 + "export-extension": "Export extension",
  856 + "file": "Extensions file",
  857 + "invalid-file-error": "Invalid extension file"
850 858 },
851 859 "fullscreen": {
852 860 "expand": "Expand to fullscreen",
... ...
... ... @@ -66,7 +66,7 @@ function ExtensionsTableWidgetController($scope, $translate, utils) {
66 66 }
67 67 vm.ctx.widgetTitle = vm.extensionsTitle;
68 68
69   - vm.ctx.widgetActions = [vm.addAction, vm.searchAction, vm.refreshAction];
  69 + vm.ctx.widgetActions = [vm.importExtensionsAction, vm.exportExtensionsAction, vm.addAction, vm.searchAction, vm.refreshAction];
70 70 }
71 71
72 72 function updateDatasources() {
... ... @@ -78,7 +78,7 @@ function ExtensionsTableWidgetController($scope, $translate, utils) {
78 78
79 79 vm.changeSelectedSource = function(source) {
80 80 vm.selectedSource = source;
81   - }
  81 + };
82 82
83 83 vm.searchAction = {
84 84 name: "action.search",
... ... @@ -96,7 +96,7 @@ function ExtensionsTableWidgetController($scope, $translate, utils) {
96 96 $scope.$broadcast("refreshExtensions", vm.selectedSource);
97 97 },
98 98 icon: "refresh"
99   - }
  99 + };
100 100
101 101 vm.addAction = {
102 102 name: "action.add",
... ... @@ -105,7 +105,25 @@ function ExtensionsTableWidgetController($scope, $translate, utils) {
105 105 $scope.$broadcast("addExtension", vm.selectedSource);
106 106 },
107 107 icon: "add"
108   - }
  108 + };
  109 +
  110 + vm.exportExtensionsAction = {
  111 + name: "extension.export-extensions-configuration",
  112 + show: true,
  113 + onAction: function() {
  114 + $scope.$broadcast("exportExtensions", vm.selectedSource);
  115 + },
  116 + icon: "file_download"
  117 + };
  118 +
  119 + vm.importExtensionsAction = {
  120 + name: "extension.import-extensions-configuration",
  121 + show: true,
  122 + onAction: function() {
  123 + $scope.$broadcast("importExtensions", vm.selectedSource);
  124 + },
  125 + icon: "file_upload"
  126 + };
109 127
110 128 $scope.$on("filterMode", function($event, mode) {
111 129 vm.tabsHidden = mode;
... ...