/*
* Copyright © 2016 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 'angular-material-data-table/dist/md-data-table.min.css';
import './attribute-table.scss';
/* eslint-disable import/no-unresolved, import/default */
import attributeTableTemplate from './attribute-table.tpl.html';
import addAttributeDialogTemplate from './add-attribute-dialog.tpl.html';
import addWidgetToDashboardDialogTemplate from './add-widget-to-dashboard-dialog.tpl.html';
import editAttributeValueTemplate from './edit-attribute-value.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
import EditAttributeValueController from './edit-attribute-value.controller';
/*@ngInject*/
export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog,
$document, $translate, utils, types, deviceService, widgetService) {
var linker = function (scope, element, attrs) {
var template = $templateCache.get(attributeTableTemplate);
element.html(template);
scope.types = types;
scope.attributeScopes = types.deviceAttributesScope;
var getAttributeScopeByValue = function(attributeScopeValue) {
if (scope.types.latestTelemetry.value === attributeScopeValue) {
return scope.types.latestTelemetry;
}
for (var attrScope in scope.attributeScopes) {
if (scope.attributeScopes[attrScope].value === attributeScopeValue) {
return scope.attributeScopes[attrScope];
}
}
}
scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope);
scope.attributes = {
count: 0,
data: []
};
scope.selectedAttributes = [];
scope.mode = 'default'; // 'widget'
scope.subscriptionId = null;
scope.query = {
order: 'key',
limit: 5,
page: 1,
search: null
};
scope.$watch("deviceId", function(newVal, prevVal) {
if (newVal && !angular.equals(newVal, prevVal)) {
scope.resetFilter();
scope.getDeviceAttributes();
}
});
scope.$watch("attributeScope", function(newVal, prevVal) {
if (newVal && !angular.equals(newVal, prevVal)) {
scope.mode = 'default';
scope.query.search = null;
scope.selectedAttributes = [];
scope.getDeviceAttributes();
}
});
scope.resetFilter = function() {
scope.mode = 'default';
scope.query.search = null;
scope.selectedAttributes = [];
scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope);
}
scope.enterFilterMode = function() {
scope.query.search = '';
}
scope.exitFilterMode = function() {
scope.query.search = null;
scope.getDeviceAttributes();
}
scope.$watch("query.search", function(newVal, prevVal) {
if (!angular.equals(newVal, prevVal) && scope.query.search != null) {
scope.getDeviceAttributes();
}
});
function success(attributes, update) {
scope.attributes = attributes;
if (!update) {
scope.selectedAttributes = [];
}
}
scope.getDeviceAttributes = function(forceUpdate) {
if (scope.attributesDeferred) {
scope.attributesDeferred.resolve();
}
if (scope.deviceId && scope.attributeScope) {
scope.checkSubscription();
scope.attributesDeferred = deviceService.getDeviceAttributes(scope.deviceId, scope.attributeScope.value,
scope.query, function(attributes, update) {
success(attributes, update || forceUpdate);
}
);
} else {
var deferred = $q.defer();
scope.attributesDeferred = deferred;
success({
count: 0,
data: []
});
deferred.resolve();
}
}
scope.checkSubscription = function() {
var newSubscriptionId = null;
if (scope.deviceId && scope.attributeScope.clientSide && scope.mode != 'widget') {
newSubscriptionId = deviceService.subscribeForDeviceAttributes(scope.deviceId, scope.attributeScope.value);
}
if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) {
deviceService.unsubscribeForDeviceAttributes(scope.subscriptionId);
}
scope.subscriptionId = newSubscriptionId;
}
scope.editAttribute = function($event, attribute) {
if (!scope.attributeScope.clientSide) {
$event.stopPropagation();
$mdEditDialog.show({
controller: EditAttributeValueController,
templateUrl: editAttributeValueTemplate,
locals: {attributeValue: attribute.value,
save: function (model) {
var updatedAttribute = angular.copy(attribute);
updatedAttribute.value = model.value;
deviceService.saveDeviceAttributes(scope.deviceId, scope.attributeScope.value, [updatedAttribute]).then(
function success() {
scope.getDeviceAttributes();
}
);
}},
targetEvent: $event
});
}
}
scope.addAttribute = function($event) {
if (!scope.attributeScope.clientSide) {
$event.stopPropagation();
$mdDialog.show({
controller: 'AddAttributeDialogController',
controllerAs: 'vm',
templateUrl: addAttributeDialogTemplate,
parent: angular.element($document[0].body),
locals: {deviceId: scope.deviceId, attributeScope: scope.attributeScope.value},
fullscreen: true,
targetEvent: $event
}).then(function () {
scope.getDeviceAttributes();
});
}
}
scope.deleteAttributes = function($event) {
if (!scope.attributeScope.clientSide) {
$event.stopPropagation();
var confirm = $mdDialog.confirm()
.targetEvent($event)
.title($translate.instant('attribute.delete-attributes-title', {count: scope.selectedAttributes.length}, 'messageformat'))
.htmlContent($translate.instant('attribute.delete-attributes-text'))
.ariaLabel($translate.instant('attribute.delete-attributes'))
.cancel($translate.instant('action.no'))
.ok($translate.instant('action.yes'));
$mdDialog.show(confirm).then(function () {
deviceService.deleteDeviceAttributes(scope.deviceId, scope.attributeScope.value, scope.selectedAttributes).then(
function success() {
scope.selectedAttributes = [];
scope.getDeviceAttributes();
}
)
});
}
}
scope.nextWidget = function() {
if (scope.widgetsCarousel.index < scope.widgetsList.length-1) {
scope.widgetsCarousel.index++;
}
}
scope.prevWidget = function() {
if (scope.widgetsCarousel.index > 0) {
scope.widgetsCarousel.index--;
}
}
scope.enterWidgetMode = function() {
if (scope.widgetsIndexWatch) {
scope.widgetsIndexWatch();
scope.widgetsIndexWatch = null;
}
if (scope.widgetsBundleWatch) {
scope.widgetsBundleWatch();
scope.widgetsBundleWatch = null;
}
scope.mode = 'widget';
scope.checkSubscription();
scope.widgetsList = [];
scope.widgetsListCache = [];
scope.widgetsLoaded = false;
scope.widgetsCarousel = {
index: 0
}
scope.widgetsBundle = null;
scope.deviceAliases = {};
scope.deviceAliases['1'] = {alias: scope.deviceName, deviceId: scope.deviceId};
var dataKeyType = scope.attributeScope === types.latestTelemetry ?
types.dataKeyType.timeseries : types.dataKeyType.attribute;
var datasource = {
type: types.datasourceType.device,
deviceAliasId: '1',
dataKeys: []
}
var i = 0;
for (var attr in scope.selectedAttributes) {
var attribute = scope.selectedAttributes[attr];
var dataKey = {
name: attribute.key,
label: attribute.key,
type: dataKeyType,
color: utils.getMaterialColor(i),
settings: {},
_hash: Math.random()
}
datasource.dataKeys.push(dataKey);
i++;
}
scope.widgetsIndexWatch = scope.$watch('widgetsCarousel.index', function(newVal, prevVal) {
if (scope.mode === 'widget' && (newVal != prevVal)) {
var index = scope.widgetsCarousel.index;
for (var i = 0; i < scope.widgetsList.length; i++) {
scope.widgetsList[i].splice(0, scope.widgetsList[i].length);
if (i === index) {
scope.widgetsList[i].push(scope.widgetsListCache[i][0]);
}
}
}
});
scope.widgetsBundleWatch = scope.$watch('widgetsBundle', function(newVal, prevVal) {
if (scope.mode === 'widget' && (scope.firstBundle === true || newVal != prevVal)) {
scope.widgetsList = [];
scope.widgetsListCache = [];
scope.widgetsCarousel.index = 0;
scope.firstBundle = false;
if (scope.widgetsBundle) {
scope.widgetsLoaded = false;
var bundleAlias = scope.widgetsBundle.alias;
var isSystem = scope.widgetsBundle.tenantId.id === types.id.nullUid;
widgetService.getBundleWidgetTypes(scope.widgetsBundle.alias, isSystem).then(
function success(widgetTypes) {
for (var i = 0; i < widgetTypes.length; i++) {
var widgetType = widgetTypes[i];
var widgetInfo = widgetService.toWidgetInfo(widgetType);
var sizeX = widgetInfo.sizeX*2;
var sizeY = widgetInfo.sizeY*2;
var col = Math.floor(Math.max(0, (20 - sizeX)/2));
var widget = {
isSystemType: isSystem,
bundleAlias: bundleAlias,
typeAlias: widgetInfo.alias,
type: widgetInfo.type,
title: widgetInfo.widgetName,
sizeX: sizeX,
sizeY: sizeY,
row: 0,
col: col,
config: angular.fromJson(widgetInfo.defaultConfig)
};
widget.config.title = widgetInfo.widgetName;
widget.config.datasources = [datasource];
var length;
if (scope.attributeScope === types.latestTelemetry && widgetInfo.type !== types.widgetType.rpc.value) {
length = scope.widgetsListCache.push([widget]);
scope.widgetsList.push(length === 1 ? [widget] : []);
} else if (widgetInfo.type === types.widgetType.latest.value) {
length = scope.widgetsListCache.push([widget]);
scope.widgetsList.push(length === 1 ? [widget] : []);
}
}
scope.widgetsLoaded = true;
}
);
}
}
});
widgetService.getWidgetsBundleByAlias(types.systemBundleAlias.cards).then(
function success(widgetsBundle) {
scope.firstBundle = true;
scope.widgetsBundle = widgetsBundle;
}
);
}
scope.exitWidgetMode = function() {
if (scope.widgetsBundleWatch) {
scope.widgetsBundleWatch();
scope.widgetsBundleWatch = null;
}
if (scope.widgetsIndexWatch) {
scope.widgetsIndexWatch();
scope.widgetsIndexWatch = null;
}
scope.mode = 'default';
scope.getDeviceAttributes(true);
}
scope.addWidgetToDashboard = function($event) {
if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) {
var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0];
$event.stopPropagation();
$mdDialog.show({
controller: 'AddWidgetToDashboardDialogController',
controllerAs: 'vm',
templateUrl: addWidgetToDashboardDialogTemplate,
parent: angular.element($document[0].body),
locals: {deviceId: scope.deviceId, deviceName: scope.deviceName, widget: angular.copy(widget)},
fullscreen: true,
targetEvent: $event
}).then(function () {
});
}
}
scope.loading = function() {
return $rootScope.loading;
}
$compile(element.contents())(scope);
}
return {
restrict: "E",
link: linker,
scope: {
deviceId: '=',
deviceName: '=',
disableAttributeScopeSelection: '@?'
}
};
}