diff --git a/application/src/main/data/json/system/widget_bundles/control_widgets.json b/application/src/main/data/json/system/widget_bundles/control_widgets.json index 44f7d52ebf..9f1b8cea10 100644 --- a/application/src/main/data/json/system/widget_bundles/control_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/control_widgets.json @@ -50,7 +50,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\",\n \"default\": 0\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\",\n \"default\": 100\n },\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"number\",\n \"default\": 50\n },\n \"title\": {\n \"title\": \"Knob title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"Set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"minValue\", \"maxValue\", \"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"minValue\",\n \"maxValue\",\n \"initialValue\",\n \"title\",\n \"getValueMethod\",\n \"setValueMethod\",\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { @@ -66,7 +66,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { @@ -82,7 +82,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { @@ -98,7 +98,7 @@ "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", "dataKeySettingsSchema": "{}\n", - "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" } }, { diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 744fb368a9..b58a2c42e5 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -123,10 +123,10 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 2.4.1 to 2.4.2 ..."); databaseUpgradeService.upgradeDatabase("2.4.1"); - case "2.4.2.1": - log.info("Upgrading ThingsBoard from version 2.4.2.1 to 2.4.3 ..."); + case "2.4.2": + log.info("Upgrading ThingsBoard from version 2.4.2 to 2.4.3 ..."); - databaseUpgradeService.upgradeDatabase("2.4.2.1"); + databaseUpgradeService.upgradeDatabase("2.4.2"); log.info("Updating system data..."); diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java index 7d0b22db67..01fb0c083d 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java @@ -278,7 +278,7 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { } catch (InvalidQueryException e) {} log.info("Schema updated."); break; - case "2.4.2.1": + case "2.4.2": log.info("Updating schema ..."); String updateAlarmTableStmt = "alter table alarm add propagate_relation_types text"; try { diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index d686b172cf..b9e9504462 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -196,7 +196,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { log.info("Schema updated."); } break; - case "2.4.2.1": + case "2.4.2": try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { log.info("Updating schema ..."); try { diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 0a6ce7f158..35925fedae 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -71,10 +71,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.common.data.DataConstants.ACTIVITY_EVENT; -import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.DataConstants.*; /** * Created by ashvayka on 01.05.18. @@ -344,6 +341,7 @@ public class DefaultDeviceStateService implements DeviceStateService { if (stateData != null) { DeviceState state = stateData.getState(); stateData.getState().setLastActivityTime(lastReportedActivity); + stateData.getMetaData().putValue("scope", SERVER_SCOPE); pushRuleEngineMessage(stateData, ACTIVITY_EVENT); save(deviceId, LAST_ACTIVITY_TIME, lastReportedActivity); deviceLastSavedActivity.put(deviceId, lastReportedActivity); diff --git a/application/src/main/scripts/install/upgrade_dev_db.sh b/application/src/main/scripts/install/upgrade_dev_db.sh new file mode 100755 index 0000000000..31c68ddf88 --- /dev/null +++ b/application/src/main/scripts/install/upgrade_dev_db.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# +# 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. +# + +for i in "$@" +do +case $i in + --fromVersion=*) + FROM_VERSION="${i#*=}" + shift + ;; + *) + # unknown option + ;; +esac +done + +if [[ -z "${FROM_VERSION// }" ]]; then + echo "--fromVersion parameter is invalid or unspecified!" + echo "Usage: upgrade_dev_db.sh --fromVersion={VERSION}" + exit 1 +else + fromVersion="${FROM_VERSION// }" +fi + +BASE=${project.basedir}/target +CONF_FOLDER=${BASE}/conf +jarfile="${BASE}/thingsboard-${project.version}-boot.jar" +installDir=${BASE}/data +loadDemo=true + + +export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@" +export LOADER_PATH=${BASE}/conf,${BASE}/extensions +export SQL_DATA_FOLDER=${SQL_DATA_FOLDER:-/tmp} + + +run_user="$USER" + +sudo -u "$run_user" -s /bin/sh -c "java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \ + -Dinstall.data_dir=${installDir} \ + -Dinstall.load_demo=${loadDemo} \ + -Dspring.jpa.hibernate.ddl-auto=none \ + -Dinstall.upgrade=true \ + -Dinstall.upgrade.from_version=${fromVersion} \ + -Dlogging.config=logback.xml \ + org.springframework.boot.loader.PropertiesLauncher" + +if [ $? -ne 0 ]; then + echo "ThingsBoard DB installation failed!" +else + echo "ThingsBoard DB installed successfully!" +fi + +exit $? diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index 603363b350..bcc89a0e4e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -71,6 +71,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { public void onMsg(TbContext ctx, TbMsg msg) { if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || DataConstants.ATTRIBUTES_DELETED.equals(msg.getType()) || + DataConstants.ACTIVITY_EVENT.equals(msg.getType()) || SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); @@ -87,7 +88,8 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { long endTime = entityView.getEndTimeMs(); if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || - SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { + DataConstants.ACTIVITY_EVENT.equals(msg.getType()) || + SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType()) ) { Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())); List filteredAttributes = attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList()); diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js index f1b0513ec6..83848e2817 100644 --- a/ui/src/app/api/alarm.service.js +++ b/ui/src/app/api/alarm.service.js @@ -47,6 +47,7 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { saveAlarm: saveAlarm, ackAlarm: ackAlarm, clearAlarm: clearAlarm, + deleteAlarm: deleteAlarm, getAlarms: getAlarms, getHighestAlarmSeverity: getHighestAlarmSeverity, pollAlarms: pollAlarms, @@ -132,6 +133,21 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { return deferred.promise; } + function deleteAlarm(alarmId, ignoreErrors, config) { + var deferred = $q.defer(); + var url = '/api/alarm/' + alarmId; + if (!config) { + config = {}; + } + config = Object.assign(config, { ignoreErrors: ignoreErrors }); + $http.delete(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + function getAlarms(entityType, entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, ascOrder, config) { var deferred = $q.defer(); var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit; diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index 5ce4fd7108..51336ee374 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -848,7 +848,50 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device return deferred.promise; } + function getEntityFieldKeys (entityType, searchText) { + let entityFieldKeys = []; + let query = searchText.toLowerCase(); + switch(entityType) { + case types.entityType.user: + entityFieldKeys.push(types.entityField.name.keyName); + entityFieldKeys.push(types.entityField.email.keyName); + entityFieldKeys.push(types.entityField.firstName.keyName); + entityFieldKeys.push(types.entityField.lastName.keyName); + break; + case types.entityType.tenant: + case types.entityType.customer: + entityFieldKeys.push(types.entityField.title.keyName); + entityFieldKeys.push(types.entityField.email.keyName); + entityFieldKeys.push(types.entityField.country.keyName); + entityFieldKeys.push(types.entityField.state.keyName); + entityFieldKeys.push(types.entityField.city.keyName); + entityFieldKeys.push(types.entityField.address.keyName); + entityFieldKeys.push(types.entityField.address2.keyName); + entityFieldKeys.push(types.entityField.zip.keyName); + entityFieldKeys.push(types.entityField.phone.keyName); + break; + case types.entityType.entityView: + entityFieldKeys.push(types.entityField.name.keyName); + entityFieldKeys.push(types.entityField.type.keyName); + break; + case types.entityType.device: + case types.entityType.asset: + entityFieldKeys.push(types.entityField.name.keyName); + entityFieldKeys.push(types.entityField.type.keyName); + entityFieldKeys.push(types.entityField.label.keyName); + break; + case types.entityType.dashboard: + entityFieldKeys.push(types.entityField.title.keyName); + break; + } + + return query ? entityFieldKeys.filter((entityField) => entityField.toLowerCase().indexOf(query) === 0) : entityFieldKeys; + } + function getEntityKeys(entityType, entityId, query, type, config) { + if (type === types.dataKeyType.entityField) { + return $q.when(getEntityFieldKeys(entityType, query)); + } var deferred = $q.defer(); var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/keys/'; if (type === types.dataKeyType.timeseries) { diff --git a/ui/src/app/api/subscription.js b/ui/src/app/api/subscription.js index 89f8aae309..86ab823294 100644 --- a/ui/src/app/api/subscription.js +++ b/ui/src/app/api/subscription.js @@ -332,7 +332,8 @@ export default class Subscription { for (var a = 0; a < datasource.dataKeys.length; a++) { var dataKey = datasource.dataKeys[a]; - dataKey.hidden = false; + dataKey.hidden = dataKey.settings.hideDataByDefault ? true : false; + dataKey.inLegend = dataKey.settings.removeFromLegend ? false : true; dataKey.pattern = angular.copy(dataKey.label); if (this.comparisonEnabled && dataKey.settings.comparisonSettings && dataKey.settings.comparisonSettings.showValuesForComparison) { @@ -349,6 +350,11 @@ export default class Subscription { dataKey: dataKey, data: [] }; + if (dataKey.type === this.ctx.types.dataKeyType.entityField) { + if(datasource.entity && datasource.entity[this.ctx.types.entityField[dataKey.name].value]){ + datasourceData.data.push([Date.now(), datasource.entity[this.ctx.types.entityField[dataKey.name].value]]); + } + } this.data.push(datasourceData); this.hiddenData.push({data: []}); if (this.displayLegend) { @@ -877,8 +883,14 @@ export default class Subscription { }; } + var entityFieldKey = false; + for (var a = 0; a < datasource.dataKeys.length; a++) { - this.data[index + a].data = []; + if (datasource.dataKeys[a].type !== this.ctx.types.dataKeyType.entityField) { + this.data[index + a].data = []; + } else { + entityFieldKey = true; + } } index += datasource.dataKeys.length; @@ -890,7 +902,7 @@ export default class Subscription { } var forceUpdate = false; - if (datasource.unresolvedStateEntity || + if (datasource.unresolvedStateEntity || entityFieldKey || !datasource.dataKeys.length || (datasource.type === this.ctx.types.datasourceType.entity && !datasource.entityId) ) { diff --git a/ui/src/app/api/time.service.js b/ui/src/app/api/time.service.js index 6b2e3f7687..56b7f0735b 100644 --- a/ui/src/app/api/time.service.js +++ b/ui/src/app/api/time.service.js @@ -281,6 +281,9 @@ function TimeService($translate, $http, $q, types) { var historyTimewindow = { + hideInterval: timewindow.hideInterval || false, + hideAggregation: timewindow.hideAggregation || false, + hideAggInterval: timewindow.hideAggInterval || false, history: { fixedTimewindow: { startTimeMs: startTimeMs, diff --git a/ui/src/app/app.config.js b/ui/src/app/app.config.js index c38deae93b..d441d87d8b 100644 --- a/ui/src/app/app.config.js +++ b/ui/src/app/app.config.js @@ -78,7 +78,8 @@ export default function AppConfig($provide, $mdIconProvider.iconSet('mdi', mdiIconSet); ngMdIconServiceProvider - .addShape('alpha-a-circle-outline', ''); + .addShape('alpha-a-circle-outline', '') + .addShape('alpha-e-circle-outline', ''); configureTheme(); @@ -170,4 +171,4 @@ export default function AppConfig($provide, return aliases; } -} \ No newline at end of file +} diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index e6e65bbecf..6b11af555f 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -322,7 +322,8 @@ export default angular.module('thingsboard.types', []) timeseries: "timeseries", attribute: "attribute", function: "function", - alarm: "alarm" + alarm: "alarm", + entityField: "entityField" }, contentType: { "JSON": { @@ -467,6 +468,84 @@ export default angular.module('thingsboard.types', []) list: 'entity.type-current-customer' } }, + entityField: { + createdTime: { + keyName: 'createdTime', + name: 'entity-field.created-time', + value: 'createdTime', + time: true + }, + name: { + keyName: 'name', + name: 'entity-field.name', + value: 'name' + }, + type: { + keyName: 'type', + name: 'entity-field.type', + value: 'type' + }, + firstName: { + keyName: 'firstName', + name: 'entity-field.first-name', + value: 'firstName' + }, + lastName: { + keyName: 'lastName', + name: 'entity-field.last-name', + value: 'lastName' + }, + email: { + keyName: 'email', + name: 'entity-field.email', + value: 'email' + }, + title: { + keyName: 'title', + name: 'entity-field.title', + value: 'title' + }, + country: { + keyName: 'country', + name: 'entity-field.country', + value: 'country' + }, + state: { + keyName: 'state', + name: 'entity-field.state', + value: 'state' + }, + city: { + keyName: 'city', + name: 'entity-field.city', + value: 'city' + }, + address: { + keyName: 'address', + name: 'entity-field.address', + value: 'address' + }, + address2: { + keyName: 'address2', + name: 'entity-field.address2', + value: 'address2' + }, + zip: { + keyName: 'zip', + name: 'entity-field.zip', + value: 'zip' + }, + phone: { + keyName: 'phone', + name: 'entity-field.phone', + value: 'phone' + }, + label: { + keyName: 'label', + name: 'entity-field.label', + value: 'label' + } + }, entitySearchDirection: { from: "FROM", to: "TO" diff --git a/ui/src/app/components/datakey-config.tpl.html b/ui/src/app/components/datakey-config.tpl.html index 0b5b11d690..f8da179141 100644 --- a/ui/src/app/components/datakey-config.tpl.html +++ b/ui/src/app/components/datakey-config.tpl.html @@ -16,9 +16,7 @@ --> - - \ No newline at end of file + diff --git a/ui/src/app/components/datasource-entity.directive.js b/ui/src/app/components/datasource-entity.directive.js index 9ed05b8812..844e60e97e 100644 --- a/ui/src/app/components/datasource-entity.directive.js +++ b/ui/src/app/components/datasource-entity.directive.js @@ -124,7 +124,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc var alarmDataKeys = []; for (var d in ngModelCtrl.$viewValue.dataKeys) { var dataKey = ngModelCtrl.$viewValue.dataKeys[d]; - if ((dataKey.type === types.dataKeyType.timeseries) || (dataKey.type === types.dataKeyType.attribute)) { + if ((dataKey.type === types.dataKeyType.timeseries) || (dataKey.type === types.dataKeyType.attribute) || (dataKey.type === types.dataKeyType.entityField)) { dataKeys.push(dataKey); } else if (dataKey.type === types.dataKeyType.alarm) { alarmDataKeys.push(dataKey); @@ -219,7 +219,7 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc w.triggerHandler('resize'); } }).then(function (newDataKey) { - if ((newDataKey.type === types.dataKeyType.timeseries) || (newDataKey.type === types.dataKeyType.attribute)) { + if ((newDataKey.type === types.dataKeyType.timeseries) || (newDataKey.type === types.dataKeyType.attribute) || (newDataKey.type === types.dataKeyType.entityField)) { let index = scope.dataKeys.indexOf(dataKey); scope.dataKeys[index] = newDataKey; } else if (newDataKey.type === types.dataKeyType.alarm) { @@ -246,10 +246,16 @@ function DatasourceEntity($compile, $templateCache, $q, $mdDialog, $window, $doc items.push({ name: dataKeys[i], type: types.dataKeyType.timeseries }); } if (scope.widgetType == types.widgetType.latest.value) { - scope.fetchEntityKeys({entityAliasId: scope.entityAlias.id, query: searchText, type: types.dataKeyType.attribute}) - .then(function (dataKeys) { + var keysType = [types.dataKeyType.attribute, types.dataKeyType.entityField]; + var promises = []; + keysType.forEach((type) => { + promises.push(scope.fetchEntityKeys({entityAliasId: scope.entityAlias.id, query: searchText, type: type})); + }); + $q.all(promises).then(function (dataKeys) { for (var i = 0; i < dataKeys.length; i++) { - items.push({ name: dataKeys[i], type: types.dataKeyType.attribute }); + for (var j = 0; j < dataKeys[i].length; j++) { + items.push({name: dataKeys[i][j], type: keysType[i]}); + } } deferred.resolve(items); }, function (e) { diff --git a/ui/src/app/components/datasource-entity.tpl.html b/ui/src/app/components/datasource-entity.tpl.html index fe0d23eef7..a167d313ee 100644 --- a/ui/src/app/components/datasource-entity.tpl.html +++ b/ui/src/app/components/datasource-entity.tpl.html @@ -43,6 +43,10 @@ {{'datakey.attributes' | translate }} + + {{'datakey.entityField' | translate }} + + {{'datakey.timeseries' | translate }} @@ -60,6 +64,10 @@ {{'datakey.attributes' | translate }} + + {{'datakey.entityField' | translate }} + + {{'datakey.timeseries' | translate }} @@ -81,6 +89,10 @@ {{'datakey.attributes' | translate }} + + + {{'datakey.entityField' | translate }} + {{'datakey.timeseries' | translate }} diff --git a/ui/src/app/components/legend.directive.js b/ui/src/app/components/legend.directive.js index 76ffdb4e78..bed10e3f52 100644 --- a/ui/src/app/components/legend.directive.js +++ b/ui/src/app/components/legend.directive.js @@ -46,7 +46,9 @@ function Legend($compile, $templateCache, types) { scope.isRowDirection = scope.legendConfig.direction === types.direction.row.value; scope.toggleHideData = function(index) { - scope.legendData.keys[index].dataKey.hidden = !scope.legendData.keys[index].dataKey.hidden; + if (!scope.legendData.keys[index].dataKey.settings.disableDataHiding) { + scope.legendData.keys[index].dataKey.hidden = !scope.legendData.keys[index].dataKey.hidden; + } } $compile(element.contents())(scope); diff --git a/ui/src/app/components/legend.tpl.html b/ui/src/app/components/legend.tpl.html index 157835729b..d77bb1193c 100644 --- a/ui/src/app/components/legend.tpl.html +++ b/ui/src/app/components/legend.tpl.html @@ -27,7 +27,8 @@ - + - + {{ 'legend.min' | translate }} - {{ legendData.data[legendKey.dataIndex].min }} + + {{ legendData.data[legendKey.dataIndex].min }} + {{ 'legend.max' | translate }} - {{ legendData.data[legendKey.dataIndex].max }} + + {{ legendData.data[legendKey.dataIndex].max }} + {{ 'legend.avg' | translate }} - {{ legendData.data[legendKey.dataIndex].avg }} + + {{ legendData.data[legendKey.dataIndex].avg }} + {{ 'legend.total' | translate }} - {{ legendData.data[legendKey.dataIndex].total }} + + {{ legendData.data[legendKey.dataIndex].total }} + diff --git a/ui/src/app/components/timewindow-button.tpl.html b/ui/src/app/components/timewindow-button.tpl.html index 6edf9c76a0..5549fd35e6 100644 --- a/ui/src/app/components/timewindow-button.tpl.html +++ b/ui/src/app/components/timewindow-button.tpl.html @@ -15,7 +15,7 @@ limitations under the License. --> - + {{model.displayValue}} \ No newline at end of file diff --git a/ui/src/app/components/timewindow.directive.js b/ui/src/app/components/timewindow.directive.js index 0d06de8679..991a3838ff 100644 --- a/ui/src/app/components/timewindow.directive.js +++ b/ui/src/app/components/timewindow.directive.js @@ -97,7 +97,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM element.html(template); scope.openEditMode = function (event) { - if (scope.disabled) { + if (scope.timewindowDisabled) { return; } var position; @@ -212,6 +212,10 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM } } + scope.isTimewindowDisabled = function () { + return scope.disabled || (!scope.isEdit && scope.model.hideInterval && scope.model.hideAggregation && scope.model.hideAggInterval); + } + ngModelCtrl.$render = function () { scope.model = timeService.defaultTimewindow(); if (ngModelCtrl.$viewValue) { @@ -243,6 +247,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM model.hideAggregation = value.hideAggregation; model.hideAggInterval = value.hideAggInterval; } + scope.timewindowDisabled = scope.isTimewindowDisabled(); scope.updateDisplayValue(); }; diff --git a/ui/src/app/components/timewindow.tpl.html b/ui/src/app/components/timewindow.tpl.html index 0e0475b9cd..2889addd5a 100644 --- a/ui/src/app/components/timewindow.tpl.html +++ b/ui/src/app/components/timewindow.tpl.html @@ -16,7 +16,7 @@ -->
- + {{ 'timewindow.edit' | translate }} @@ -28,7 +28,7 @@ {{model.displayValue}} - + {{ 'timewindow.edit' | translate }} diff --git a/ui/src/app/components/widget/widget-config.directive.js b/ui/src/app/components/widget/widget-config.directive.js index 470726a835..2fe97ce6d6 100644 --- a/ui/src/app/components/widget/widget-config.directive.js +++ b/ui/src/app/components/widget/widget-config.directive.js @@ -423,10 +423,10 @@ function WidgetConfig($compile, $templateCache, $rootScope, $translate, $timeout } var label = chip; - if (type === types.dataKeyType.alarm) { - var alarmField = types.alarmFields[chip]; - if (alarmField) { - label = $translate.instant(alarmField.name)+''; + if (type === types.dataKeyType.alarm || type === types.dataKeyType.entityField) { + var keyField = type === types.dataKeyType.alarm ? types.alarmFields[chip] : types.entityField[chip]; + if (keyField) { + label = $translate.instant(keyField.name)+''; } } label = scope.genNextLabel(label); diff --git a/ui/src/app/locale/locale.constant-el_GR.json b/ui/src/app/locale/locale.constant-el_GR.json index b590c70e47..f3051e98c1 100644 --- a/ui/src/app/locale/locale.constant-el_GR.json +++ b/ui/src/app/locale/locale.constant-el_GR.json @@ -1102,6 +1102,22 @@ "copyId": "Αντιγραφή ID ομάδας οντοτήτων", "idCopiedMessage": "Το ID της ομάδας οντοτήτων έχει αντιγραφεί στο πρόχειρο" }, + "entity-field": { + "created-time": "Δημιουργήθηκε", + "name": "Όνομα", + "type": "Τύπος", + "first-name": "Όνομα", + "last-name": "Επίθετο", + "email": "Email", + "title": "Τίτλος", + "country": "Χώρα", + "state": "Νομός", + "city": "Πόλη", + "address": "Διεύθυνση", + "address2": "Διεύθυνση 2", + "zip": "Τ.Κ.", + "phone": "Τηλέφωνο" + }, "entity-view": { "entity-view": "Όψη Οντότητας", "entity-view-required": "Απαιτείται προβολή οντότητας.", @@ -2603,4 +2619,4 @@ "el_GR": "Ελληνικά" } } -} \ No newline at end of file +} diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 67f3fb09de..6310438128 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -815,6 +815,23 @@ "no-data": "No data to display", "columns-to-display": "Columns to Display" }, + "entity-field": { + "created-time": "Created time", + "name": "Name", + "type": "Type", + "first-name": "First name", + "last-name": "Last name", + "email": "Email", + "title": "Title", + "country": "Country", + "state": "State", + "city": "City", + "address": "Address", + "address2": "Address 2", + "zip": "Zip", + "phone": "Phone", + "label": "Label" + }, "entity-view": { "entity-view": "Entity View", "entity-view-required": "Entity view is required.", diff --git a/ui/src/app/locale/locale.constant-es_ES.json b/ui/src/app/locale/locale.constant-es_ES.json index d3d1c4042f..5cebe22ef6 100644 --- a/ui/src/app/locale/locale.constant-es_ES.json +++ b/ui/src/app/locale/locale.constant-es_ES.json @@ -808,6 +808,22 @@ "no-data": "No hay datos para mostrar", "columns-to-display": "Columnas a mostrar" }, + "entity-field": { + "created-time": "Tiempo de creación", + "name": "Nombre", + "type": "Tipo", + "first-name": "Nombre", + "last-name": "Apellido", + "email": "Correo electrónico", + "title": "Título", + "country": "País", + "state": "Estado", + "city": "Ciudad", + "address": "Dirección", + "address2": "Dirección 2", + "zip": "Código postal", + "phone": "Teléfono" + }, "entity-view": { "entity-view": "Vista de entidad", "entity-view-required": "Vista de entidad es requerido.", diff --git a/ui/src/app/locale/locale.constant-fr_FR.json b/ui/src/app/locale/locale.constant-fr_FR.json index b25a532927..5c922bfd49 100644 --- a/ui/src/app/locale/locale.constant-fr_FR.json +++ b/ui/src/app/locale/locale.constant-fr_FR.json @@ -809,6 +809,22 @@ "use-entity-name-filter": "Utiliser un filtre", "user-name-starts-with": "Utilisateurs dont les noms commencent par '{{prefix}}'" }, + "entity-field": { + "address": "Adresse", + "address2": "Adresse 2", + "city": "Ville", + "country": "Pays", + "created-time": "Heure de création", + "email": "Email", + "first-name": "Prénom", + "last-name": "Nom de famille", + "name": "Nom", + "phone": "Téléphone", + "state": "Prov", + "title": "Titre", + "type": "Type", + "zip": "Code postal" + }, "entity-view": { "add": "Ajouter une vue d'entité", "add-alias": "Ajouter un alias de vue d'entité", diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index 3aaa3042c5..41fa69a3dc 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -661,7 +661,7 @@ "delete-device-title": "Вы точно хотите удалить устройство '{{deviceName}}'?", "delete-device-text": "Внимание, после подтверждения устройство и все связанные с ним данные будут безвозвратно утеряны.", "delete-devices-title": "Вы точно хотите удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} }?", - "delete-devices-action-title": "Удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} } }", + "delete-devices-action-title": "Удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} }", "delete-devices-text": "Внимание, после подтверждения выбранные устройства и все связанные с ними данные будут безвозвратно утеряны..", "unassign-device-title": "Вы точно хотите отозвать устройство '{{deviceName}}'?", "unassign-device-text": "После подтверждения устройство будет недоступно клиенту.", @@ -814,6 +814,23 @@ "no-data": "Нет данных для отображения", "columns-to-display": "Отобразить следующие колонки" }, + "entity-field": { + "created-time": "Время создания", + "name": "Название", + "type": "Тип", + "first-name": "Имя", + "last-name": "Фамилия", + "email": "Электронная почта", + "title": "Название", + "country": "Страна", + "state": "Штат/Область", + "city": "Город", + "address": "Адрес", + "address2": "Адрес 2", + "zip": "Индекс", + "phone": "Телефон", + "label": "Метка" + }, "entity-view": { "entity-view": "Представление Объекта", "entity-view-required": "Представление объекта обязательно.", diff --git a/ui/src/app/locale/locale.constant-uk_UA.json b/ui/src/app/locale/locale.constant-uk_UA.json index cbbaabd666..49fd45a409 100644 --- a/ui/src/app/locale/locale.constant-uk_UA.json +++ b/ui/src/app/locale/locale.constant-uk_UA.json @@ -956,6 +956,23 @@ "list-of-integrations": "{ count, plural, 1 {Одна інтеграція} other {Список # інтеграцій} }", "integration-name-starts-with": "Інтеграції, імена яких починаються з '{{prefix}}'" }, + "entity-field": { + "created-time": "Час створення", + "name": "Ім'я", + "type": "Тип", + "first-name": "Ім'я", + "last-name": "Прізвище", + "email": "Електронна пошта", + "title": "Назва", + "country": "Країна", + "state": "Штат", + "city": "Місто", + "address": "Адреса", + "address2": "Адреса 2", + "zip": "Zip", + "phone": "Телефон", + "label": "Мітка" + }, "entity-group": { "entity-group": "Група сутності", "details": "Деталі", diff --git a/ui/src/app/widget/lib/flot-widget.js b/ui/src/app/widget/lib/flot-widget.js index 08496d574b..063c68a4da 100644 --- a/ui/src/app/widget/lib/flot-widget.js +++ b/ui/src/app/widget/lib/flot-widget.js @@ -139,12 +139,7 @@ export default class TbFlot { return seriesHover.index === seriesIndex; }); if (found && found.length) { - let timestamp; - if (!angular.isNumber(hoverInfo[0].time) || (found[0].time < hoverInfo[0].time)) { - timestamp = parseInt(hoverInfo[1].time); - } else { - timestamp = parseInt(hoverInfo[0].time); - } + let timestamp = parseInt(found[0].time); let date = moment(timestamp).format('YYYY-MM-DD HH:mm:ss'); let dateDiv = $('
' + date + '
'); dateDiv.css({ @@ -1213,7 +1208,35 @@ export default class TbFlot { } static get pieDatakeySettingsSchema() { - return {} + return { + "schema": { + "type": "object", + "title": "DataKeySettings", + "properties": { + "hideDataByDefault": { + "title": "Data is hidden by default", + "type": "boolean", + "default": false + }, + "disableDataHiding": { + "title": "Disable data hiding", + "type": "boolean", + "default": false + }, + "removeFromLegend": { + "title": "Remove datakey from legend", + "type": "boolean", + "default": false + } + }, + "required": [] + }, + "form": [ + "hideDataByDefault", + "disableDataHiding", + "removeFromLegend" + ] + }; } static datakeySettingsSchema(defaultShowLines, chartType) { @@ -1228,6 +1251,21 @@ export default class TbFlot { "type": "boolean", "default": false }, + "hideDataByDefault": { + "title": "Data is hidden by default", + "type": "boolean", + "default": false + }, + "disableDataHiding": { + "title": "Disable data hiding", + "type": "boolean", + "default": false + }, + "removeFromLegend": { + "title": "Remove datakey from legend", + "type": "boolean", + "default": false + }, "showLines": { "title": "Show lines", "type": "boolean", @@ -1316,6 +1354,9 @@ export default class TbFlot { "required": ["showLines", "fillLines", "showPoints"] }, "form": [ + "hideDataByDefault", + "disableDataHiding", + "removeFromLegend", "excludeFromStacking", "showLines", "fillLines", diff --git a/ui/src/app/widget/lib/rpc/knob.scss b/ui/src/app/widget/lib/rpc/knob.scss index 568994d391..19009d9227 100644 --- a/ui/src/app/widget/lib/rpc/knob.scss +++ b/ui/src/app/widget/lib/rpc/knob.scss @@ -26,12 +26,9 @@ $minmax-height: percentage(.04) !default; $minmax-container-margin-pct: percentage(.18) !default; $minmax-container-margin-bottom-pct: percentage(.12) !default; -$background-color: #e6e7e8 !default; - .tb-knob { width: 100%; height: 100%; - background: $background-color; .knob { position: relative; diff --git a/ui/src/app/widget/lib/rpc/led-indicator.scss b/ui/src/app/widget/lib/rpc/led-indicator.scss index 7fe825dab7..4d058cffb9 100644 --- a/ui/src/app/widget/lib/rpc/led-indicator.scss +++ b/ui/src/app/widget/lib/rpc/led-indicator.scss @@ -17,12 +17,9 @@ $error-height: 14px !default; -$background-color: #e6e7e8 !default; - .tb-led-indicator { width: 100%; height: 100%; - background: $background-color; .title-container { .led-title { diff --git a/ui/src/app/widget/lib/rpc/round-switch.scss b/ui/src/app/widget/lib/rpc/round-switch.scss index bc2cc4a929..50eaa6db75 100644 --- a/ui/src/app/widget/lib/rpc/round-switch.scss +++ b/ui/src/app/widget/lib/rpc/round-switch.scss @@ -17,12 +17,9 @@ $error-height: 14px !default; -$background-color: #e6e7e8 !default; - .tb-round-switch { width: 100%; height: 100%; - background: $background-color; .title-container { .switch-title { diff --git a/ui/src/app/widget/lib/rpc/switch.scss b/ui/src/app/widget/lib/rpc/switch.scss index 72500ff03e..7045a4bf05 100644 --- a/ui/src/app/widget/lib/rpc/switch.scss +++ b/ui/src/app/widget/lib/rpc/switch.scss @@ -18,14 +18,11 @@ $thumb-checked-img: url("./svg/thumb-checked.svg") !default; $thumb-bar-img: url("./svg/thumb-bar.svg") !default; $thumb-bar-checked-img: url("./svg/thumb-bar-checked.svg") !default; -$background-color: #e6e7e8 !default; - $error-height: 14px !default; .tb-switch { width: 100%; height: 100%; - background: $background-color; .error-container { position: absolute;