multiple-input-widget.js 13 KB
/*
 * Copyright © 2016-2020 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 './multiple-input-widget.scss';

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

import multipleInputWidgetTemplate from './multiple-input-widget.tpl.html';

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

export default angular.module('thingsboard.widgets.multipleInputWidget', [])
    .directive('tbMultipleInputWidget', MultipleInputWidget)
    .name;

/*@ngInject*/
function MultipleInputWidget() {
    return {
        restrict: "E",
        scope: true,
        bindToController: {
            formId: '=',
            ctx: '='
        },
        controller: MultipleInputWidgetController,
        controllerAs: 'vm',
        templateUrl: multipleInputWidgetTemplate
    };
}

/*@ngInject*/
function MultipleInputWidgetController($q, $scope, $translate, attributeService, toast, types, utils) {
    var vm = this;

    vm.entityDetected = false;
    vm.isAllParametersValid = true;

    vm.sources = [];
    vm.datasources = null;

    vm.discardAll = discardAll;
    vm.inputChanged = inputChanged;
    vm.save = save;
    vm.getGroupTitle = getGroupTitle;

    $scope.$watch('vm.ctx', function () {
        if (vm.ctx && vm.ctx.defaultSubscription) {
            vm.settings = vm.ctx.settings;
            vm.widgetConfig = vm.ctx.widgetConfig;
            vm.subscription = vm.ctx.defaultSubscription;
            vm.datasources = vm.subscription.datasources;
            initializeConfig();
            updateDatasources();
        }
    });

    $scope.$on('multiple-input-data-updated', function (event, formId) {
        if (vm.formId == formId) {
            updateWidgetData(vm.subscription.data);
            $scope.$digest();
        }
    });

    $scope.$on('multiple-input-resize', function (event, formId) {
        if (vm.formId == formId) {
            updateWidgetDisplaying();
        }
    });

    function discardAll() {
        for (var i = 0; i < vm.sources.length; i++) {
            for (var j = 0; j < vm.sources[i].keys.length; j++) {
                vm.sources[i].keys[j].data.currentValue = vm.sources[i].keys[j].data.originalValue;
            }
        }
        $scope.multipleInputForm.$setPristine();
    }

    function inputChanged(source, key) {
        if (!vm.settings.showActionButtons) {
            if (!key.settings.required || (key.settings.required && key.data && angular.isDefined(key.data.currentValue))) {
                var dataToSave = {
                    datasource: source.datasource,
                    keys: [key]
                };
                vm.save(dataToSave);
            }
        }
    }

    function save(dataToSave) {
        var tasks = [];
        var config = {
            ignoreLoading: !vm.settings.showActionButtons
        };
        var data;
        if (dataToSave) {
            data = [dataToSave];
        } else {
            data = vm.sources;
        }
        for (let i = 0; i < data.length; i++) {
            var serverAttributes = [], sharedAttributes = [], telemetry = [];
            for (let j = 0; j < data[i].keys.length; j++) {
                var key = data[i].keys[j];
                if ((key.data.currentValue !== key.data.originalValue) || vm.settings.updateAllValues) {
                    var attribute = {
                        key: key.name
                    };
                    if (key.data.currentValue) {
                        switch (key.settings.dataKeyValueType) {
                            case 'dateTime':
                            case 'date':
                                attribute.value = key.data.currentValue.getTime();
                                break;
                            case 'time':
                                attribute.value = key.data.currentValue.getTime() - moment().startOf('day').valueOf();//eslint-disable-line
                                break;
                            default:
                                attribute.value = key.data.currentValue;
                        }
                    } else {
                        if (key.data.currentValue === '') {
                            attribute.value = null;
                        } else {
                            attribute.value = key.data.currentValue;
                        }
                    }

                    switch (key.settings.dataKeyType) {
                        case 'shared':
                            sharedAttributes.push(attribute);
                            break;
                        case 'timeseries':
                            telemetry.push(attribute);
                            break;
                        default:
                            serverAttributes.push(attribute);
                    }
                }
            }
            if (serverAttributes.length) {
                tasks.push(attributeService.saveEntityAttributes(
                    data[i].datasource.entityType,
                    data[i].datasource.entityId,
                    types.attributesScope.server.value,
                    serverAttributes,
                    config));
            }
            if (sharedAttributes.length) {
                tasks.push(attributeService.saveEntityAttributes(
                    data[i].datasource.entityType,
                    data[i].datasource.entityId,
                    types.attributesScope.shared.value,
                    sharedAttributes,
                    config));
            }
            if (telemetry.length) {
                tasks.push(attributeService.saveEntityTimeseries(
                    data[i].datasource.entityType,
                    data[i].datasource.entityId,
                    types.latestTelemetry.value,
                    telemetry,
                    config));
            }
        }

        if (tasks.length) {
            $q.all(tasks).then(
                function success() {
                    $scope.multipleInputForm.$setPristine();
                    if (vm.settings.showResultMessage) {
                        toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(vm.ctx.$container), 'bottom left');
                    }
                },
                function fail() {
                    if (vm.settings.showResultMessage) {
                        toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(vm.ctx.$container), 'bottom left');
                    }
                }
            );
        } else {
            $scope.multipleInputForm.$setPristine();
        }
    }

    function initializeConfig() {

        if (vm.settings.widgetTitle && vm.settings.widgetTitle.length) {
            vm.widgetTitle = utils.customTranslation(vm.settings.widgetTitle, vm.settings.widgetTitle);
        } else {
            vm.widgetTitle = vm.ctx.widgetConfig.title;
        }

        vm.ctx.widgetTitle = vm.widgetTitle;

        vm.settings.groupTitle = vm.settings.groupTitle || "${entityName}";

        //For backward compatibility
        if (angular.isUndefined(vm.settings.showActionButtons)) {
            vm.settings.showActionButtons = true;
        }
        if (angular.isUndefined(vm.settings.fieldsAlignment)) {
            vm.settings.fieldsAlignment = 'row';
        }
        if (angular.isUndefined(vm.settings.fieldsInRow)) {
            vm.settings.fieldsInRow = 2;
        }
        //For backward compatibility

        vm.isVerticalAlignment = !(vm.settings.fieldsAlignment === 'row');

        if (!vm.isVerticalAlignment && vm.settings.fieldsInRow) {
            vm.inputWidthSettings = 100 / vm.settings.fieldsInRow + '%';
        }
        updateWidgetDisplaying();
    }

    function updateDatasources() {
        if (vm.datasources && vm.datasources.length) {
            vm.entityDetected = true;
            for (var i = 0; i < vm.datasources.length; i++) {
                var datasource = vm.datasources[i];
                var source = {
                    datasource: datasource,
                    keys: []
                };
                if (datasource.type === types.datasourceType.entity) {
                    for (var j = 0; j < datasource.dataKeys.length; j++) {
                        if ((datasource.entityType !== types.entityType.device) && (datasource.dataKeys[j].settings.dataKeyType == 'shared')) {
                            vm.isAllParametersValid = false;
                        }
                        source.keys.push(datasource.dataKeys[j]);
                        if (source.keys[j].units) {
                            source.keys[j].label += ' (' + source.keys[j].units + ')';
                        }
                        source.keys[j].data = {};

                        //For backward compatibility
                        if (angular.isUndefined(source.keys[j].settings.dataKeyType)) {
                            if (vm.settings.attributesShared) {
                                source.keys[j].settings.dataKeyType = 'shared';
                            } else {
                                source.keys[j].settings.dataKeyType = 'server';
                            }
                        }

                        if (angular.isUndefined(source.keys[j].settings.dataKeyValueType)) {
                            if (source.keys[j].settings.inputTypeNumber) {
                                source.keys[j].settings.dataKeyValueType = 'double';
                            } else {
                                source.keys[j].settings.dataKeyValueType = 'string';
                            }
                        }

                        if (angular.isUndefined(source.keys[j].settings.isEditable)) {
                            if (source.keys[j].settings.readOnly) {
                                source.keys[j].settings.isEditable = 'readonly';
                            } else {
                                source.keys[j].settings.isEditable = 'editable';
                            }
                        }
                        //For backward compatibility

                    }
                } else {
                    vm.entityDetected = false;
                }
                vm.sources.push(source);
            }
        }
    }

    function updateWidgetData(data) {
        var dataIndex = 0;
        for (var i = 0; i < vm.sources.length; i++) {
            var source = vm.sources[i];
            for (var j = 0; j < source.keys.length; j++) {
                var keyData = data[dataIndex].data;
                var key = source.keys[j];
                if (keyData && keyData.length) {
                    var value;
                    switch (key.settings.dataKeyValueType) {
                        case 'dateTime':
                        case 'date':
                            value = moment(keyData[0][1]).toDate(); // eslint-disable-line
                            break;
                        case 'time':
                            value = moment().startOf('day').add(keyData[0][1], 'ms').toDate(); // eslint-disable-line
                            break;
                        case 'booleanCheckbox':
                        case 'booleanSwitch':
                            value = (keyData[0][1] === 'true');
                            break;
                        default:
                            value = keyData[0][1];
                    }

                    key.data = {
                        currentValue: value,
                        originalValue: value
                    };
                }

                if (key.settings.isEditable === 'editable' && key.settings.disabledOnDataKey) {
                    var conditions = data.filter((item) => {
                        return item.dataKey.name === key.settings.disabledOnDataKey;
                    });
                    if (conditions && conditions.length) {
                        if (conditions[0].data.length) {
                            if (conditions[0].data[0][1] === 'false') {
                                key.settings.disabledOnCondition = true;
                            } else {
                                key.settings.disabledOnCondition = !conditions[0].data[0][1];
                            }
                        }
                    }
                }
                dataIndex++;
            }
        }
    }

    function updateWidgetDisplaying() {
        vm.changeAlignment = (vm.ctx.$container[0].offsetWidth < 620);
        vm.smallWidthContainer = (vm.ctx.$container[0].offsetWidth < 420);
    }

    function getGroupTitle(datasource) {
        return utils.createLabelFromDatasource(datasource, vm.settings.groupTitle);
    }
}