import-export.service.js

813 lines | 32.568 kB Blame History Raw Download
/*
 * Copyright © 2016-2018 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.
 */
/* eslint-disable import/no-unresolved, import/default */

import importDialogTemplate from './import-dialog.tpl.html';
import entityAliasesTemplate from '../entity/alias/entity-aliases.tpl.html';

/* eslint-enable import/no-unresolved, import/default */


/* eslint-disable no-undef, angular/window-service, angular/document-service */

/*@ngInject*/
export default function ImportExport($log, $translate, $q, $mdDialog, $document, $http, itembuffer, utils, types,
                                     dashboardUtils, entityService, dashboardService, ruleChainService, widgetService, toast, attributeService) {


    var service = {
        exportDashboard: exportDashboard,
        importDashboard: importDashboard,
        exportWidget: exportWidget,
        importWidget: importWidget,
        exportRuleChain: exportRuleChain,
        importRuleChain: importRuleChain,
        exportWidgetType: exportWidgetType,
        importWidgetType: importWidgetType,
        exportWidgetsBundle: exportWidgetsBundle,
        importWidgetsBundle: importWidgetsBundle,
        exportExtension: exportExtension,
        importExtension: importExtension,
        exportToPc: exportToPc
    };

    return service;

    // Widgets bundle functions

    function exportWidgetsBundle(widgetsBundleId) {
        widgetService.getWidgetsBundle(widgetsBundleId).then(
            function success(widgetsBundle) {
                var bundleAlias = widgetsBundle.alias;
                var isSystem = widgetsBundle.tenantId.id === types.id.nullUid;
                widgetService.getBundleWidgetTypes(bundleAlias, isSystem).then(
                    function success (widgetTypes) {
                        prepareExport(widgetsBundle);
                        var widgetsBundleItem = {
                           widgetsBundle:  prepareExport(widgetsBundle),
                           widgetTypes: []
                        };
                        for (var t in widgetTypes) {
                            var widgetType = widgetTypes[t];
                            if (angular.isDefined(widgetType.bundleAlias)) {
                                delete widgetType.bundleAlias;
                            }
                            widgetsBundleItem.widgetTypes.push(prepareExport(widgetType));
                        }
                        var name = widgetsBundle.title;
                        name = name.toLowerCase().replace(/\W/g,"_");
                        exportToPc(widgetsBundleItem, name + '.json');
                    },
                    function fail (rejection) {
                        var message = rejection;
                        if (!message) {
                            message = $translate.instant('error.unknown-error');
                        }
                        toast.showError($translate.instant('widgets-bundle.export-failed-error', {error: message}));
                    }
                );
            },
            function fail(rejection) {
                var message = rejection;
                if (!message) {
                    message = $translate.instant('error.unknown-error');
                }
                toast.showError($translate.instant('widgets-bundle.export-failed-error', {error: message}));
            }
        );
    }

    function importNextWidgetType(widgetTypes, bundleAlias, index, deferred) {
        if (!widgetTypes || widgetTypes.length <= index) {
            deferred.resolve();
        } else {
            var widgetType = widgetTypes[index];
            widgetType.bundleAlias = bundleAlias;
            widgetService.saveImportedWidgetType(widgetType).then(
                function success() {
                    index++;
                    importNextWidgetType(widgetTypes, bundleAlias, index, deferred);
                },
                function fail() {
                    deferred.reject();
                }
            );

        }
    }

    function importWidgetsBundle($event) {
        var deferred = $q.defer();
        openImportDialog($event, 'widgets-bundle.import', 'widgets-bundle.widgets-bundle-file').then(
            function success(widgetsBundleItem) {
                if (!validateImportedWidgetsBundle(widgetsBundleItem)) {
                    toast.showError($translate.instant('widgets-bundle.invalid-widgets-bundle-file-error'));
                    deferred.reject();
                } else {
                    var widgetsBundle = widgetsBundleItem.widgetsBundle;
                    widgetService.saveWidgetsBundle(widgetsBundle).then(
                        function success(savedWidgetsBundle) {
                            var bundleAlias = savedWidgetsBundle.alias;
                            var widgetTypes = widgetsBundleItem.widgetTypes;
                            importNextWidgetType(widgetTypes, bundleAlias, 0, deferred);
                        },
                        function fail() {
                            deferred.reject();
                        }
                    );
                }
            },
            function fail() {
                deferred.reject();
            }
        );
        return deferred.promise;
    }

    function validateImportedWidgetsBundle(widgetsBundleItem) {
        if (angular.isUndefined(widgetsBundleItem.widgetsBundle)) {
            return false;
        }
        if (angular.isUndefined(widgetsBundleItem.widgetTypes)) {
            return false;
        }
        var widgetsBundle = widgetsBundleItem.widgetsBundle;
        if (angular.isUndefined(widgetsBundle.title)) {
            return false;
        }
        var widgetTypes = widgetsBundleItem.widgetTypes;
        for (var t in widgetTypes) {
            var widgetType = widgetTypes[t];
            if (!validateImportedWidgetType(widgetType)) {
                return false;
            }
        }

        return true;
    }

    // Widget type functions

    function exportWidgetType(widgetTypeId) {
        widgetService.getWidgetTypeById(widgetTypeId).then(
            function success(widgetType) {
                if (angular.isDefined(widgetType.bundleAlias)) {
                    delete widgetType.bundleAlias;
                }
                var name = widgetType.name;
                name = name.toLowerCase().replace(/\W/g,"_");
                exportToPc(prepareExport(widgetType), name + '.json');
            },
            function fail(rejection) {
                var message = rejection;
                if (!message) {
                    message = $translate.instant('error.unknown-error');
                }
                toast.showError($translate.instant('widget-type.export-failed-error', {error: message}));
            }
        );
    }

    function importWidgetType($event, bundleAlias) {
        var deferred = $q.defer();
        openImportDialog($event, 'widget-type.import', 'widget-type.widget-type-file').then(
            function success(widgetType) {
                if (!validateImportedWidgetType(widgetType)) {
                    toast.showError($translate.instant('widget-type.invalid-widget-type-file-error'));
                    deferred.reject();
                } else {
                    widgetType.bundleAlias = bundleAlias;
                    widgetService.saveImportedWidgetType(widgetType).then(
                        function success() {
                            deferred.resolve();
                        },
                        function fail() {
                            deferred.reject();
                        }
                    );
                }
            },
            function fail() {
                deferred.reject();
            }
        );
        return deferred.promise;
    }

    function validateImportedWidgetType(widgetType) {
        if (angular.isUndefined(widgetType.name)
            || angular.isUndefined(widgetType.descriptor))
        {
            return false;
        }
        return true;
    }

    // Rule chain functions

    function exportRuleChain(ruleChainId) {
        ruleChainService.getRuleChain(ruleChainId).then(
            (ruleChain) => {
                ruleChainService.getRuleChainMetaData(ruleChainId).then(
                    (ruleChainMetaData) => {
                        var ruleChainExport = {
                            ruleChain: prepareRuleChain(ruleChain),
                            metadata: prepareRuleChainMetaData(ruleChainMetaData)
                        };
                        var name = ruleChain.name;
                        name = name.toLowerCase().replace(/\W/g,"_");
                        exportToPc(ruleChainExport, name + '.json');
                    },
                    (rejection) => {
                        processExportRuleChainRejection(rejection);
                    }
                );
            },
            (rejection) => {
                processExportRuleChainRejection(rejection);
            }
        );
    }

    function prepareRuleChain(ruleChain) {
        ruleChain = prepareExport(ruleChain);
        if (ruleChain.firstRuleNodeId) {
            ruleChain.firstRuleNodeId = null;
        }
        ruleChain.root = false;
        return ruleChain;
    }

    function prepareRuleChainMetaData(ruleChainMetaData) {
        delete ruleChainMetaData.ruleChainId;
        for (var i=0;i<ruleChainMetaData.nodes.length;i++) {
            var node = ruleChainMetaData.nodes[i];
            delete node.ruleChainId;
            ruleChainMetaData.nodes[i] = prepareExport(node);
        }
        return ruleChainMetaData;
    }

    function processExportRuleChainRejection(rejection) {
        var message = rejection;
        if (!message) {
            message = $translate.instant('error.unknown-error');
        }
        toast.showError($translate.instant('rulechain.export-failed-error', {error: message}));
    }

    function importRuleChain($event) {
        var deferred = $q.defer();
        openImportDialog($event, 'rulechain.import', 'rulechain.rulechain-file').then(
            function success(ruleChainImport) {
                if (!validateImportedRuleChain(ruleChainImport)) {
                    toast.showError($translate.instant('rulechain.invalid-rulechain-file-error'));
                    deferred.reject();
                } else {
                    deferred.resolve(ruleChainImport);
                }
            },
            function fail() {
                deferred.reject();
            }
        );
        return deferred.promise;
    }

    function validateImportedRuleChain(ruleChainImport) {
        if (angular.isUndefined(ruleChainImport.ruleChain)) {
            return false;
        }
        if (angular.isUndefined(ruleChainImport.metadata)) {
            return false;
        }
        if (angular.isUndefined(ruleChainImport.ruleChain.name)) {
            return false;
        }
        return true;
    }

    // Widget functions

    function exportWidget(dashboard, sourceState, sourceLayout, widget) {
        var widgetItem = itembuffer.prepareWidgetItem(dashboard, sourceState, sourceLayout, widget);
        var name = widgetItem.widget.config.title;
        name = name.toLowerCase().replace(/\W/g,"_");
        exportToPc(prepareExport(widgetItem), name + '.json');
    }

    function prepareAliasesInfo(aliasesInfo) {
        var datasourceAliases = aliasesInfo.datasourceAliases;
        var targetDeviceAliases = aliasesInfo.targetDeviceAliases;
        var datasourceIndex;
        if (datasourceAliases || targetDeviceAliases) {
            if (datasourceAliases) {
                for (datasourceIndex in datasourceAliases) {
                    datasourceAliases[datasourceIndex] = prepareEntityAlias(datasourceAliases[datasourceIndex]);
                }
            }
            if (targetDeviceAliases) {
                for (datasourceIndex in targetDeviceAliases) {
                    targetDeviceAliases[datasourceIndex] = prepareEntityAlias(targetDeviceAliases[datasourceIndex]);
                }
            }
        }
        return aliasesInfo;
    }

    function prepareEntityAlias(aliasInfo) {
        var alias;
        var filter;
        if (aliasInfo.deviceId) {
            alias = aliasInfo.aliasName;
            filter = {
                type: types.aliasFilterType.entityList.value,
                entityType: types.entityType.device,
                entityList: [aliasInfo.deviceId],
                resolveMultiple: false
            };
        } else if (aliasInfo.deviceFilter) {
            alias = aliasInfo.aliasName;
            filter = {
                type: aliasInfo.deviceFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value,
                entityType: types.entityType.device,
                resolveMultiple: false
            }
            if (filter.type == types.aliasFilterType.entityList.value) {
                filter.entityList = aliasInfo.deviceFilter.deviceList
            } else {
                filter.entityNameFilter = aliasInfo.deviceFilter.deviceNameFilter;
            }
        } else if (aliasInfo.entityFilter) {
            alias = aliasInfo.aliasName;
            filter = {
                type: aliasInfo.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value,
                entityType: aliasInfo.entityType,
                resolveMultiple: false
            }
            if (filter.type == types.aliasFilterType.entityList.value) {
                filter.entityList = aliasInfo.entityFilter.entityList;
            } else {
                filter.entityNameFilter = aliasInfo.entityFilter.entityNameFilter;
            }
        } else {
            alias = aliasInfo.alias;
            filter = aliasInfo.filter;
        }
        return {
            alias: alias,
            filter: filter
        };
    }

    function importWidget($event, dashboard, targetState, targetLayoutFunction, onAliasesUpdateFunction) {
        var deferred = $q.defer();
        openImportDialog($event, 'dashboard.import-widget', 'dashboard.widget-file').then(
            function success(widgetItem) {
                if (!validateImportedWidget(widgetItem)) {
                    toast.showError($translate.instant('dashboard.invalid-widget-file-error'));
                    deferred.reject();
                } else {
                    var widget = widgetItem.widget;
                    widget = dashboardUtils.validateAndUpdateWidget(widget);
                    var aliasesInfo = prepareAliasesInfo(widgetItem.aliasesInfo);
                    var originalColumns = widgetItem.originalColumns;
                    var originalSize = widgetItem.originalSize;

                    var datasourceAliases = aliasesInfo.datasourceAliases;
                    var targetDeviceAliases = aliasesInfo.targetDeviceAliases;
                    if (datasourceAliases || targetDeviceAliases) {
                        var entityAliases = {};
                        var datasourceAliasesMap = {};
                        var targetDeviceAliasesMap = {};
                        var aliasId;
                        var datasourceIndex;
                        if (datasourceAliases) {
                            for (datasourceIndex in datasourceAliases) {
                                aliasId = utils.guid();
                                datasourceAliasesMap[aliasId] = datasourceIndex;
                                entityAliases[aliasId] = datasourceAliases[datasourceIndex];
                                entityAliases[aliasId].id = aliasId;
                            }
                        }
                        if (targetDeviceAliases) {
                            for (datasourceIndex in targetDeviceAliases) {
                                aliasId = utils.guid();
                                targetDeviceAliasesMap[aliasId] = datasourceIndex;
                                entityAliases[aliasId] = targetDeviceAliases[datasourceIndex];
                                entityAliases[aliasId].id = aliasId;
                            }
                        }

                        var aliasIds = Object.keys(entityAliases);
                        if (aliasIds.length > 0) {
                            processEntityAliases(entityAliases, aliasIds).then(
                                function(missingEntityAliases) {
                                    if (Object.keys(missingEntityAliases).length > 0) {
                                        editMissingAliases($event, [ widget ],
                                              true, 'dashboard.widget-import-missing-aliases-title', missingEntityAliases).then(
                                            function success(updatedEntityAliases) {
                                                for (var aliasId in updatedEntityAliases) {
                                                    var entityAlias = updatedEntityAliases[aliasId];
                                                    var datasourceIndex;
                                                    if (datasourceAliasesMap[aliasId]) {
                                                        datasourceIndex = datasourceAliasesMap[aliasId];
                                                        datasourceAliases[datasourceIndex] = entityAlias;
                                                    } else if (targetDeviceAliasesMap[aliasId]) {
                                                        datasourceIndex = targetDeviceAliasesMap[aliasId];
                                                        targetDeviceAliases[datasourceIndex] = entityAlias;
                                                    }
                                                }
                                                addImportedWidget(dashboard, targetState, targetLayoutFunction, $event, widget,
                                                    aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, deferred);
                                            },
                                            function fail() {
                                                deferred.reject();
                                            }
                                        );
                                    } else {
                                        addImportedWidget(dashboard, targetState, targetLayoutFunction, $event, widget,
                                            aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, deferred);
                                    }
                                }
                            );
                        } else {
                            addImportedWidget(dashboard, targetState, targetLayoutFunction, $event, widget,
                                aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, deferred);
                        }
                    } else {
                        addImportedWidget(dashboard, targetState, targetLayoutFunction, $event, widget,
                            aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, deferred);
                    }
                }
            },
            function fail() {
                deferred.reject();
            }
        );
        return deferred.promise;
    }

    function validateImportedWidget(widgetItem) {
        if (angular.isUndefined(widgetItem.widget)
            || angular.isUndefined(widgetItem.aliasesInfo)
            || angular.isUndefined(widgetItem.originalColumns)) {
            return false;
        }
        var widget = widgetItem.widget;
        if (angular.isUndefined(widget.isSystemType) ||
            angular.isUndefined(widget.bundleAlias) ||
            angular.isUndefined(widget.typeAlias) ||
            angular.isUndefined(widget.type)) {
            return false;
        }
        return true;
    }

    function addImportedWidget(dashboard, targetState, targetLayoutFunction, event, widget,
                               aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, deferred) {
        targetLayoutFunction(event).then(
            function success(targetLayout) {
                itembuffer.addWidgetToDashboard(dashboard, targetState, targetLayout, widget,
                    aliasesInfo, onAliasesUpdateFunction, originalColumns, originalSize, -1, -1).then(
                        function() {
                            deferred.resolve(
                                {
                                    widget: widget,
                                    layoutId: targetLayout
                                }
                            );
                        }
                );
            },
            function fail() {
                deferred.reject();
            }
        );
    }

    // Dashboard functions

    function exportDashboard(dashboardId) {
        dashboardService.getDashboard(dashboardId).then(
            function success(dashboard) {
                var name = dashboard.title;
                name = name.toLowerCase().replace(/\W/g,"_");
                exportToPc(prepareDashboardExport(dashboard), name + '.json');
            },
            function fail(rejection) {
                var message = rejection;
                if (!message) {
                    message = $translate.instant('error.unknown-error');
                }
                toast.showError($translate.instant('dashboard.export-failed-error', {error: message}));
            }
        );
    }

    function prepareDashboardExport(dashboard) {
        dashboard = prepareExport(dashboard);
        delete dashboard.assignedCustomers;
        delete dashboard.publicCustomerId;
        delete dashboard.assignedCustomersText;
        delete dashboard.assignedCustomersIds;
        return dashboard;
    }

    function importDashboard($event) {
        var deferred = $q.defer();
        openImportDialog($event, 'dashboard.import', 'dashboard.dashboard-file').then(
            function success(dashboard) {
                if (!validateImportedDashboard(dashboard)) {
                    toast.showError($translate.instant('dashboard.invalid-dashboard-file-error'));
                    deferred.reject();
                } else {
                    dashboard = dashboardUtils.validateAndUpdateDashboard(dashboard);
                    var entityAliases = dashboard.configuration.entityAliases;
                    if (entityAliases) {
                        var aliasIds = Object.keys( entityAliases );
                        if (aliasIds.length > 0) {
                            processEntityAliases(entityAliases, aliasIds).then(
                                function(missingEntityAliases) {
                                    if (Object.keys( missingEntityAliases ).length > 0) {
                                        editMissingAliases($event, dashboard.configuration.widgets,
                                                false, 'dashboard.dashboard-import-missing-aliases-title', missingEntityAliases).then(
                                            function success(updatedEntityAliases) {
                                                for (var aliasId in updatedEntityAliases) {
                                                    entityAliases[aliasId] = updatedEntityAliases[aliasId];
                                                }
                                                saveImportedDashboard(dashboard, deferred);
                                            },
                                            function fail() {
                                                deferred.reject();
                                            }
                                        );
                                    } else {
                                        saveImportedDashboard(dashboard, deferred);
                                    }
                                }
                            )
                        } else {
                            saveImportedDashboard(dashboard, deferred);
                        }
                    } else {
                        saveImportedDashboard(dashboard, deferred);
                    }
                }
            },
            function fail() {
                deferred.reject();
            }
        );
        return deferred.promise;
    }

    function saveImportedDashboard(dashboard, deferred) {
        dashboardService.saveDashboard(dashboard).then(
            function success() {
                deferred.resolve();
            },
            function fail() {
                deferred.reject();
            }
        )
    }

    function validateImportedDashboard(dashboard) {
        if (angular.isUndefined(dashboard.title) || angular.isUndefined(dashboard.configuration)) {
            return false;
        }
        return true;
    }



    function exportExtension(extensionId) {

        getExtension(extensionId)
            .then(
                function success(extension) {
                    var name = extension.title;
                    name = name.toLowerCase().replace(/\W/g,"_");
                    exportToPc(prepareExport(extension), name + '.json');
                },
                function fail(rejection) {
                    var message = rejection;
                    if (!message) {
                        message = $translate.instant('error.unknown-error');
                    }
                    toast.showError($translate.instant('extension.export-failed-error', {error: message}));
                }
            );

        function getExtension(extensionId) {
            var deferred = $q.defer();
            var url = '/api/plugins/telemetry/DEVICE/' + extensionId;
            $http.get(url, null)
                .then(function success(response) {
                    deferred.resolve(response.data);
                }, function fail() {
                    deferred.reject();
                });
            return deferred.promise;
        }

    }

    function importExtension($event, options) {
        var deferred = $q.defer();
        openImportDialog($event, 'extension.import-extensions', 'extension.file')
            .then(
                function success(extension) {
                    if (!validateImportedExtension(extension)) {
                        toast.showError($translate.instant('extension.invalid-file-error'));
                        deferred.reject();
                    } else {
                        attributeService
                            .saveEntityAttributes(
                                options.entityType,
                                options.entityId,
                                types.attributesScope.shared.value,
                                [{
                                    key: "configuration",
                                    value: angular.toJson(extension)
                                }]
                            )
                            .then(function success() {
                                options.successFunc();
                            });
                    }
                },
                function fail() {
                    deferred.reject();
                }
            );
        return deferred.promise;
    }

    function validateImportedExtension(configuration) {
        if (configuration.length) {
            for (let i = 0; i < configuration.length; i++) {
                if (angular.isUndefined(configuration[i].configuration) || angular.isUndefined(configuration[i].id )|| angular.isUndefined(configuration[i].type)) {
                    return false;
                }
            }
        } else {
            return false;
        }
        return true;
    }

    function processEntityAliases(entityAliases, aliasIds) {
        var deferred = $q.defer();
        var missingEntityAliases = {};
        var index = -1;
        checkNextEntityAliasOrComplete(index, aliasIds, entityAliases, missingEntityAliases, deferred);
        return deferred.promise;
    }

    function checkNextEntityAliasOrComplete(index, aliasIds, entityAliases, missingEntityAliases, deferred) {
        index++;
        if (index == aliasIds.length) {
            deferred.resolve(missingEntityAliases);
        } else {
            checkEntityAlias(index, aliasIds, entityAliases, missingEntityAliases, deferred);
        }
    }

    function checkEntityAlias(index, aliasIds, entityAliases, missingEntityAliases, deferred) {
        var aliasId = aliasIds[index];
        var entityAlias = entityAliases[aliasId];
        entityService.checkEntityAlias(entityAlias).then(
            function(result) {
                if (result) {
                    checkNextEntityAliasOrComplete(index, aliasIds, entityAliases, missingEntityAliases, deferred);
                } else {
                    var missingEntityAlias = angular.copy(entityAlias);
                    missingEntityAlias.filter = null;
                    missingEntityAliases[aliasId] = missingEntityAlias;
                    checkNextEntityAliasOrComplete(index, aliasIds, entityAliases, missingEntityAliases, deferred);
                }
            }
        );
    }

    function editMissingAliases($event, widgets, isSingleWidget, customTitle, missingEntityAliases) {
        var deferred = $q.defer();
        $mdDialog.show({
            controller: 'EntityAliasesController',
            controllerAs: 'vm',
            templateUrl: entityAliasesTemplate,
            locals: {
                config: {
                    entityAliases: missingEntityAliases,
                    widgets: widgets,
                    isSingleWidget: isSingleWidget,
                    customTitle: customTitle,
                    disableAdd: true
                }
            },
            parent: angular.element($document[0].body),
            skipHide: true,
            fullscreen: true,
            targetEvent: $event
        }).then(function (updatedEntityAliases) {
            deferred.resolve(updatedEntityAliases);
        }, function () {
            deferred.reject();
        });
        return deferred.promise;
    }

    // Common functions

    function prepareExport(data) {
        var exportedData = angular.copy(data);
        if (angular.isDefined(exportedData.id)) {
            delete exportedData.id;
        }
        if (angular.isDefined(exportedData.createdTime)) {
            delete exportedData.createdTime;
        }
        if (angular.isDefined(exportedData.tenantId)) {
            delete exportedData.tenantId;
        }
        if (angular.isDefined(exportedData.customerId)) {
            delete exportedData.customerId;
        }
        return exportedData;
    }

    function exportToPc(data, filename) {
        if (!data) {
            $log.error('No data');
            return;
        }

        if (!filename) {
            filename = 'download.json';
        }

        if (angular.isObject(data)) {
            data = angular.toJson(data, 2);
        }

        var blob = new Blob([data], {type: 'text/json'});

        // FOR IE:

        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveOrOpenBlob(blob, filename);
        }
        else{
            var e = document.createEvent('MouseEvents'),
                a = document.createElement('a');

            a.download = filename;
            a.href = window.URL.createObjectURL(blob);
            a.dataset.downloadurl = ['text/json', a.download, a.href].join(':');
            e.initEvent('click', true, false, window,
                0, 0, 0, 0, 0, false, false, false, false, 0, null);
            a.dispatchEvent(e);
        }
    }

    function openImportDialog($event, importTitle, importFileLabel) {
        var deferred = $q.defer();
        $mdDialog.show({
            controller: 'ImportDialogController',
            controllerAs: 'vm',
            templateUrl: importDialogTemplate,
            locals: {
                importTitle: importTitle,
                importFileLabel: importFileLabel
            },
            parent: angular.element($document[0].body),
            skipHide: true,
            fullscreen: true,
            targetEvent: $event
        }).then(function (importData) {
            deferred.resolve(importData);
        }, function () {
            deferred.reject();
        });
        return deferred.promise;
    }

}

/* eslint-enable no-undef, angular/window-service, angular/document-service */