Merge branch 'master' into develop/2.2

This commit is contained in:
Igor Kulikov 2018-10-04 17:20:33 +03:00
commit d92b06584a
38 changed files with 540 additions and 432 deletions

File diff suppressed because one or more lines are too long

View File

@ -35,7 +35,7 @@
"resources": [],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema;\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}"
@ -147,10 +147,10 @@
"resources": [],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema;\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('bar');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":true,\"tooltipIndividual\":false},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}"
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":true,\"tooltipIndividual\":false,\"defaultBarWidth\":600},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}"
}
},
{
@ -163,7 +163,7 @@
"resources": [],
"templateHtml": "",
"templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema;\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n",
"settingsSchema": "{}",
"dataKeySettingsSchema": "{}",
"defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}"

View File

@ -20,7 +20,7 @@ DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer;
DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id;
DROP TABLE IF EXISTS thingsboard.entity_views;
ControllerSqlTestSuite
CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
id timeuuid,
entity_id timeuuid,

View File

@ -391,6 +391,7 @@ audit_log:
"user": "${AUDIT_LOG_MASK_USER:W}"
"rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}"
"alarm": "${AUDIT_LOG_MASK_ALARM:W}"
"entity_view": "${AUDIT_LOG_MASK_RULE_CHAIN:W}"
sink:
# Type of external sink. possible options: none, elasticsearch
type: "${AUDIT_LOG_SINK_TYPE:none}"

View File

@ -73,4 +73,6 @@ public abstract class DeviceAwareSessionContext implements SessionContext {
public Device getDevice() {
return device;
}
}

View File

@ -54,6 +54,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.CacheConstants.ASSET_CACHE;
@ -141,7 +142,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
if (entityViews != null && !entityViews.isEmpty()) {
throw new DataValidationException("Can't delete asset that is assigned to entity views!");
}
} catch (Exception e) {
} catch (ExecutionException | InterruptedException e) {
log.error("Exception while finding entity views for assetId [{}]", assetId, e);
throw new RuntimeException("Exception while finding entity views for assetId [" + assetId + "]", e);
}

View File

@ -58,6 +58,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CACHE;
@ -158,7 +159,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
if (entityViews != null && !entityViews.isEmpty()) {
throw new DataValidationException("Can't delete device that is assigned to entity views!");
}
} catch (Exception e) {
} catch (ExecutionException | InterruptedException e) {
log.error("Exception while finding entity views for deviceId [{}]", deviceId, e);
throw new RuntimeException("Exception while finding entity views for deviceId [" + deviceId + "]", e);
}

View File

@ -51,6 +51,9 @@ import javax.security.cert.X509Certificate;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.*;
import static io.netty.handler.codec.mqtt.MqttMessageType.*;
@ -75,6 +78,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
private final RelationService relationService;
private final QuotaService quotaService;
private final SslHandler sslHandler;
private final ConcurrentMap<String, Integer> mqttQoSMap;
private volatile boolean connected;
private volatile InetSocketAddress address;
private volatile GatewaySessionCtx gatewaySessionCtx;
@ -86,7 +91,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
this.relationService = relationService;
this.authService = authService;
this.adaptor = adaptor;
this.deviceSessionCtx = new DeviceSessionCtx(processor, authService, adaptor);
this.mqttQoSMap = new ConcurrentHashMap<>();
this.deviceSessionCtx = new DeviceSessionCtx(processor, authService, adaptor, mqttQoSMap);
this.sessionId = deviceSessionCtx.getSessionId().toUidStr();
this.sslHandler = sslHandler;
this.quotaService = quotaService;
@ -166,18 +172,25 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
private void handleMqttPublishMsg(String topicName, int msgId, MqttPublishMessage mqttMsg) {
try {
if (topicName.equals(GATEWAY_TELEMETRY_TOPIC)) {
gatewaySessionCtx.onDeviceTelemetry(mqttMsg);
} else if (topicName.equals(GATEWAY_ATTRIBUTES_TOPIC)) {
gatewaySessionCtx.onDeviceAttributes(mqttMsg);
} else if (topicName.equals(GATEWAY_ATTRIBUTES_REQUEST_TOPIC)) {
gatewaySessionCtx.onDeviceAttributesRequest(mqttMsg);
} else if (topicName.equals(GATEWAY_RPC_TOPIC)) {
gatewaySessionCtx.onDeviceRpcResponse(mqttMsg);
} else if (topicName.equals(GATEWAY_CONNECT_TOPIC)) {
gatewaySessionCtx.onDeviceConnect(mqttMsg);
} else if (topicName.equals(GATEWAY_DISCONNECT_TOPIC)) {
gatewaySessionCtx.onDeviceDisconnect(mqttMsg);
switch (topicName) {
case GATEWAY_TELEMETRY_TOPIC:
gatewaySessionCtx.onDeviceTelemetry(mqttMsg);
break;
case GATEWAY_ATTRIBUTES_TOPIC:
gatewaySessionCtx.onDeviceAttributes(mqttMsg);
break;
case GATEWAY_ATTRIBUTES_REQUEST_TOPIC:
gatewaySessionCtx.onDeviceAttributesRequest(mqttMsg);
break;
case GATEWAY_RPC_TOPIC:
gatewaySessionCtx.onDeviceRpcResponse(mqttMsg);
break;
case GATEWAY_CONNECT_TOPIC:
gatewaySessionCtx.onDeviceConnect(mqttMsg);
break;
case GATEWAY_DISCONNECT_TOPIC:
gatewaySessionCtx.onDeviceDisconnect(mqttMsg);
break;
}
} catch (RuntimeException | AdaptorException e) {
log.warn("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e);
@ -225,52 +238,71 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
log.trace("[{}] Processing subscription [{}]!", sessionId, mqttMsg.variableHeader().messageId());
List<Integer> grantedQoSList = new ArrayList<>();
for (MqttTopicSubscription subscription : mqttMsg.payload().topicSubscriptions()) {
String topicName = subscription.topicName();
//TODO: handle this qos level.
String topic = subscription.topicName();
MqttQoS reqQoS = subscription.qualityOfService();
try {
if (topicName.equals(DEVICE_ATTRIBUTES_TOPIC)) {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, SUBSCRIBE_ATTRIBUTES_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
grantedQoSList.add(getMinSupportedQos(reqQoS));
} else if (topicName.equals(DEVICE_RPC_REQUESTS_SUB_TOPIC)) {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, SUBSCRIBE_RPC_COMMANDS_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
grantedQoSList.add(getMinSupportedQos(reqQoS));
} else if (topicName.equals(DEVICE_RPC_RESPONSE_SUB_TOPIC)) {
grantedQoSList.add(getMinSupportedQos(reqQoS));
} else if (topicName.equals(DEVICE_ATTRIBUTES_RESPONSES_TOPIC)) {
deviceSessionCtx.setAllowAttributeResponses();
grantedQoSList.add(getMinSupportedQos(reqQoS));
} else if (topicName.equals(GATEWAY_ATTRIBUTES_TOPIC)) {
grantedQoSList.add(getMinSupportedQos(reqQoS));
} else {
log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topicName, reqQoS);
grantedQoSList.add(FAILURE.value());
switch (topic) {
case DEVICE_ATTRIBUTES_TOPIC: {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, SUBSCRIBE_ATTRIBUTES_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
registerSubQoS(topic, grantedQoSList, reqQoS);
break;
}
case DEVICE_RPC_REQUESTS_SUB_TOPIC: {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, SUBSCRIBE_RPC_COMMANDS_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
registerSubQoS(topic, grantedQoSList, reqQoS);
break;
}
case DEVICE_RPC_RESPONSE_SUB_TOPIC:
case GATEWAY_ATTRIBUTES_TOPIC:
case GATEWAY_RPC_TOPIC:
registerSubQoS(topic, grantedQoSList, reqQoS);
break;
case DEVICE_ATTRIBUTES_RESPONSES_TOPIC:
deviceSessionCtx.setAllowAttributeResponses();
registerSubQoS(topic, grantedQoSList, reqQoS);
break;
default:
log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS);
grantedQoSList.add(FAILURE.value());
break;
}
} catch (AdaptorException e) {
log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topicName, reqQoS);
log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS);
grantedQoSList.add(FAILURE.value());
}
}
ctx.writeAndFlush(createSubAckMessage(mqttMsg.variableHeader().messageId(), grantedQoSList));
}
private void registerSubQoS(String topic, List<Integer> grantedQoSList, MqttQoS reqQoS) {
grantedQoSList.add(getMinSupportedQos(reqQoS));
mqttQoSMap.put(topic, getMinSupportedQos(reqQoS));
}
private void processUnsubscribe(ChannelHandlerContext ctx, MqttUnsubscribeMessage mqttMsg) {
if (!checkConnected(ctx)) {
return;
}
log.trace("[{}] Processing subscription [{}]!", sessionId, mqttMsg.variableHeader().messageId());
for (String topicName : mqttMsg.payload().topics()) {
mqttQoSMap.remove(topicName);
try {
if (topicName.equals(DEVICE_ATTRIBUTES_TOPIC)) {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, UNSUBSCRIBE_ATTRIBUTES_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
} else if (topicName.equals(DEVICE_RPC_REQUESTS_SUB_TOPIC)) {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, UNSUBSCRIBE_RPC_COMMANDS_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
} else if (topicName.equals(DEVICE_ATTRIBUTES_RESPONSES_TOPIC)) {
deviceSessionCtx.setDisallowAttributeResponses();
switch (topicName) {
case DEVICE_ATTRIBUTES_TOPIC: {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, UNSUBSCRIBE_ATTRIBUTES_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
break;
}
case DEVICE_RPC_REQUESTS_SUB_TOPIC: {
AdaptorToSessionActorMsg msg = adaptor.convertToActorMsg(deviceSessionCtx, UNSUBSCRIBE_RPC_COMMANDS_REQUEST, mqttMsg);
processor.process(new BasicTransportToDeviceSessionActorMsg(deviceSessionCtx.getDevice(), msg));
break;
}
case DEVICE_ATTRIBUTES_RESPONSES_TOPIC:
deviceSessionCtx.setDisallowAttributeResponses();
break;
}
} catch (AdaptorException e) {
log.warn("[{}] Failed to process unsubscription [{}] to [{}]", sessionId, mqttMsg.variableHeader().messageId(), topicName);

View File

@ -170,7 +170,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
private MqttPublishMessage createMqttPublishMsg(DeviceSessionCtx ctx, String topic, JsonElement json) {
MqttFixedHeader mqttFixedHeader =
new MqttFixedHeader(MqttMessageType.PUBLISH, false, MqttQoS.AT_LEAST_ONCE, false, 0);
new MqttFixedHeader(MqttMessageType.PUBLISH, false, ctx.getQoSForTopic(topic), false, 0);
MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, ctx.nextMsgId());
ByteBuf payload = ALLOCATOR.buffer();
payload.writeBytes(GSON.toJson(json).getBytes(UTF8));

View File

@ -30,13 +30,15 @@ import org.thingsboard.server.common.transport.auth.DeviceAuthService;
import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Andrew Shvayka
*/
@Slf4j
public class DeviceSessionCtx extends DeviceAwareSessionContext {
public class DeviceSessionCtx extends MqttDeviceAwareSessionContext {
private final MqttTransportAdaptor adaptor;
private final MqttSessionId sessionId;
@ -44,8 +46,8 @@ public class DeviceSessionCtx extends DeviceAwareSessionContext {
private volatile boolean allowAttributeResponses;
private AtomicInteger msgIdSeq = new AtomicInteger(0);
public DeviceSessionCtx(SessionMsgProcessor processor, DeviceAuthService authService, MqttTransportAdaptor adaptor) {
super(processor, authService);
public DeviceSessionCtx(SessionMsgProcessor processor, DeviceAuthService authService, MqttTransportAdaptor adaptor, ConcurrentMap<String, Integer> mqttQoSMap) {
super(processor, authService, mqttQoSMap);
this.adaptor = adaptor;
this.sessionId = new MqttSessionId();
}

View File

@ -38,13 +38,15 @@ import org.thingsboard.server.transport.mqtt.MqttTransportHandler;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by ashvayka on 19.01.17.
*/
public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext {
private static final Gson GSON = new Gson();
private static final Charset UTF8 = Charset.forName("UTF-8");
@ -56,8 +58,8 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
private volatile boolean closed;
private AtomicInteger msgIdSeq = new AtomicInteger(0);
public GatewayDeviceSessionCtx(GatewaySessionCtx parent, Device device) {
super(parent.getProcessor(), parent.getAuthService(), device);
public GatewayDeviceSessionCtx(GatewaySessionCtx parent, Device device, ConcurrentMap<String, Integer> mqttQoSMap) {
super(parent.getProcessor(), parent.getAuthService(), device, mqttQoSMap);
this.parent = parent;
this.sessionId = new MqttSessionId();
}
@ -195,7 +197,7 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
private MqttPublishMessage createMqttPublishMsg(String topic, JsonElement json) {
MqttFixedHeader mqttFixedHeader =
new MqttFixedHeader(MqttMessageType.PUBLISH, false, MqttQoS.AT_LEAST_ONCE, false, 0);
new MqttFixedHeader(MqttMessageType.PUBLISH, false, getQoSForTopic(topic), false, 0);
MqttPublishVariableHeader header = new MqttPublishVariableHeader(topic, msgIdSeq.incrementAndGet());
ByteBuf payload = ALLOCATOR.buffer();
payload.writeBytes(GSON.toJson(json).getBytes(UTF8));

View File

@ -43,6 +43,7 @@ import org.thingsboard.server.transport.mqtt.MqttTransportHandler;
import org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import static org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor.validateJsonPayload;
@ -63,6 +64,7 @@ public class GatewaySessionCtx {
private final DeviceAuthService authService;
private final RelationService relationService;
private final Map<String, GatewayDeviceSessionCtx> devices;
private final ConcurrentMap<String, Integer> mqttQoSMap;
private ChannelHandlerContext channel;
public GatewaySessionCtx(SessionMsgProcessor processor, DeviceService deviceService, DeviceAuthService authService, RelationService relationService, DeviceSessionCtx gatewaySessionCtx) {
@ -73,6 +75,7 @@ public class GatewaySessionCtx {
this.gateway = gatewaySessionCtx.getDevice();
this.gatewaySessionId = gatewaySessionCtx.getSessionId();
this.devices = new HashMap<>();
this.mqttQoSMap = gatewaySessionCtx.getMqttQoSMap();
}
public void onDeviceConnect(MqttPublishMessage msg) throws AdaptorException {
@ -96,7 +99,7 @@ public class GatewaySessionCtx {
relationService.saveRelationAsync(new EntityRelation(gateway.getId(), device.getId(), "Created"));
processor.onDeviceAdded(device);
}
GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device);
GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device, mqttQoSMap);
devices.put(deviceName, ctx);
log.debug("[{}] Added device [{}] to the gateway session", gatewaySessionId, deviceName);
processor.process(new BasicTransportToDeviceSessionActorMsg(device, new BasicAdaptorToSessionActorMsg(ctx, new AttributesSubscribeMsg())));

View File

@ -0,0 +1,57 @@
/**
* 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.
*/
package org.thingsboard.server.transport.mqtt.session;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.transport.SessionMsgProcessor;
import org.thingsboard.server.common.transport.auth.DeviceAuthService;
import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
/**
* Created by ashvayka on 30.08.18.
*/
public abstract class MqttDeviceAwareSessionContext extends DeviceAwareSessionContext {
private final ConcurrentMap<String, Integer> mqttQoSMap;
public MqttDeviceAwareSessionContext(SessionMsgProcessor processor, DeviceAuthService authService, ConcurrentMap<String, Integer> mqttQoSMap) {
super(processor, authService);
this.mqttQoSMap = mqttQoSMap;
}
public MqttDeviceAwareSessionContext(SessionMsgProcessor processor, DeviceAuthService authService, Device device, ConcurrentMap<String, Integer> mqttQoSMap) {
super(processor, authService, device);
this.mqttQoSMap = mqttQoSMap;
}
public ConcurrentMap<String, Integer> getMqttQoSMap() {
return mqttQoSMap;
}
public MqttQoS getQoSForTopic(String topic) {
Integer qos = mqttQoSMap.get(topic);
if (qos != null) {
return MqttQoS.valueOf(qos);
} else {
return MqttQoS.AT_LEAST_ONCE;
}
}
}

View File

@ -251,7 +251,7 @@
"fill",
"stroke"
],
"property-no-vendor-prefix": null,
"property-no-vendor-prefix": true,
"rule-empty-line-before": ["always", {
"except": ["first-nested"],
"ignore": ["after-comment"]
@ -272,7 +272,7 @@
"selector-max-type": 5,
"selector-max-universal": 1,
"selector-no-qualifying-type": null,
"selector-no-vendor-prefix": null,
"selector-no-vendor-prefix": true,
"selector-type-no-unknown": [true, {
"ignoreTypes": [
"/^md-/",
@ -287,6 +287,6 @@
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-newline-before": "never-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-no-vendor-prefix": null
"value-no-vendor-prefix": true
}
}

View File

@ -119,7 +119,7 @@
"ng-annotate-loader": "^0.1.1",
"ngtemplate-loader": "^1.3.1",
"node-sass": "^4.5.3",
"postcss-loader": "^0.13.0",
"postcss-loader": "^3.0.0",
"raw-loader": "^0.5.1",
"react-hot-loader": "^3.0.0-beta.6",
"sass-loader": "^4.0.2",
@ -145,5 +145,19 @@
"node_modules",
"target"
]
},
"browserslist": [
"> 0.5%",
"last 2 versions",
"Firefox ESR",
"not ie <= 10",
"not ie_mob <= 10",
"not bb <= 10",
"not op_mob <= 12.1"
],
"postcss": {
"plugins": {
"autoprefixer": true
}
}
}

View File

@ -22,7 +22,7 @@ div.tb-widget {
overflow: hidden;
outline: none;
@include transition(all .2s ease-in-out);
transition: all .2s ease-in-out;
.tb-widget-title {
max-height: 60px;
@ -99,7 +99,7 @@ md-content.tb-dashboard-content {
outline: none;
.gridster-item {
@include transition(none);
transition: none;
}
}

View File

@ -20,7 +20,7 @@
}
.tb-card-item {
@include transition(all .2s ease-in-out);
transition: all .2s ease-in-out;
md-card-content {
max-height: 53px;
@ -46,7 +46,7 @@
.tb-current-item {
opacity: .5;
@include transform(scale(1.05));
transform: scale(1.05);
}
#tb-vertical-container {

View File

@ -16,7 +16,7 @@
@import "~compass-sass-mixins/lib/compass";
.md-button-toggle .md-toggle-icon.tb-toggled {
@include transform(rotateZ(180deg));
transform: rotateZ(180deg);
}
.tb-menu-toggle-list.ng-hide {
@ -28,7 +28,7 @@
z-index: 1;
overflow: hidden;
@include transition(.75s cubic-bezier(.35, 0, .25, 1));
transition: .75s cubic-bezier(.35, 0, .25, 1);
@include transition-property(height);
transition-property: height;
}

View File

@ -28,7 +28,7 @@ $input-label-float-scale: .75 !default;
line-height: 12px;
color: rgb(244, 67, 54);
@include transition(all 450ms cubic-bezier(.23, 1, .32, 1) 0ms);
transition: all 450ms cubic-bezier(.23, 1, .32, 1) 0ms;
}
.tb-container {
@ -77,14 +77,13 @@ label.tb-label {
bottom: 100%;
left: 0;
color: rgba(0, 0, 0, .54);
transition: transform $swift-ease-out-timing-function $swift-ease-out-duration, width $swift-ease-out-timing-function $swift-ease-out-duration;
transform: translate3d(0, $input-label-float-offset, 0) scale($input-label-float-scale);
transform-origin: left top;
-webkit-font-smoothing: antialiased;
@include transform(translate3d(0, $input-label-float-offset, 0) scale($input-label-float-scale));
@include transition(transform $swift-ease-out-timing-function $swift-ease-out-duration,
width $swift-ease-out-timing-function $swift-ease-out-duration);
&.tb-focused {
color: rgb(96, 125, 139);
}

View File

@ -53,7 +53,7 @@
margin: auto 0 auto auto;
background-size: 100% auto;
@include transition(transform .3s, ease-in-out);
transition: transform .3s, ease-in-out;
}
.tb-side-menu .md-button {

View File

@ -244,13 +244,18 @@ function ManageWidgetActionsController($rootScope, $scope, $document, $mdDialog,
vm.widgetActions[actionSourceId] = targetActions;
}
if (prevActionId) {
var index = getActionIndex(prevActionId, vm.allActions);
if (index > -1) {
vm.allActions[index] = action;
const indexInTarget = getActionIndex(prevActionId, targetActions);
const indexInAllActions = getActionIndex(prevActionId, vm.allActions);
if (indexInTarget > -1) {
targetActions[indexInTarget] = widgetAction;
} else if (indexInAllActions > -1) {
const prevActionSourceId = vm.allActions[indexInAllActions].actionSourceId;
const index = getActionIndex(prevActionId,vm.widgetActions[prevActionSourceId]);
vm.widgetActions[prevActionSourceId].splice(index,1);
targetActions.push(widgetAction);
}
index = getActionIndex(prevActionId, targetActions);
if (index > -1) {
targetActions[index] = widgetAction;
if (indexInAllActions > -1) {
vm.allActions[indexInAllActions] = action;
}
} else {
vm.allActions.push(action);

View File

@ -16,12 +16,12 @@
.tb-dashboard-assigned-customers {
display: block;
display: -webkit-box;
display: -webkit-box; /* stylelint-disable-line value-no-vendor-prefix */
height: 34px;
margin-bottom: 4px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
-webkit-box-orient: vertical; /* stylelint-disable-line property-no-vendor-prefix */
}

View File

@ -31,7 +31,7 @@ tb-dashboard-toolbar {
&.md-fab {
opacity: 1;
@include transition(opacity .3s cubic-bezier(.55,0,.55,.2));
transition: opacity .3s cubic-bezier(.55, 0, .55, .2);
.md-fab-toolbar-background {
background-color: $primary-default !important;
@ -50,7 +50,7 @@ tb-dashboard-toolbar {
line-height: 36px;
opacity: .5;
@include transition(opacity .3s cubic-bezier(.55,0,.55,.2) .2s);
transition: opacity .3s cubic-bezier(.55, 0, .55, .2) .2s;
md-icon {
position: absolute;

View File

@ -75,13 +75,13 @@ section.tb-dashboard-toolbar {
&.tb-dashboard-toolbar-opened {
right: 0;
// @include transition(right .3s cubic-bezier(.55,0,.55,.2));
// transition: right .3s cubic-bezier(.55, 0, .55, .2);
}
&.tb-dashboard-toolbar-closed {
right: 18px;
@include transition(right .3s cubic-bezier(.55,0,.55,.2) .2s);
transition: right .3s cubic-bezier(.55, 0, .55, .2) .2s;
}
}
@ -102,14 +102,14 @@ section.tb-dashboard-toolbar {
margin-top: $toolbar-height;
}
@include transition(margin-top .3s cubic-bezier(.55,0,.55,.2));
transition: margin-top .3s cubic-bezier(.55, 0, .55, .2);
}
}
&.tb-dashboard-toolbar-closed {
margin-top: 0;
@include transition(margin-top .3s cubic-bezier(.55,0,.55,.2) .2s);
transition: margin-top .3s cubic-bezier(.55, 0, .55, .2) .2s;
}
.tb-dashboard-layouts {
@ -133,7 +133,7 @@ section.tb-powered-by-footer {
position: absolute;
right: 25px;
bottom: 5px;
z-index: 3;
z-index: 30;
pointer-events: none;
span {

View File

@ -146,7 +146,7 @@
ng-style="{minWidth: vm.rightLayoutWidth(),
maxWidth: vm.rightLayoutWidth(),
height: vm.rightLayoutHeight(),
zIndex: 12}"
zIndex: 25}"
md-component-id="right-dashboard-layout"
aria-label="Right dashboard layout"
md-is-open="vm.rightLayoutOpened"

View File

@ -42,7 +42,7 @@
border: none;
opacity: .75;
@include transition(opacity .35s);
transition: opacity .35s;
}
a:hover,

View File

@ -84,9 +84,6 @@
.tb-panel-title {
min-width: 150px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@ -163,10 +160,6 @@
.fc-canvas {
min-width: 100%;
min-height: 100%;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
outline: none;
-webkit-touch-callout: none;
@ -441,13 +434,7 @@
}
.fc-noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
user-select: none;
}
.fc-edge-label {
@ -495,7 +482,6 @@
font-weight: 600;
text-align: center;
white-space: nowrap;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
span {

View File

@ -29,7 +29,7 @@ md-dialog.tb-node-script-test-dialog {
}
.tb-split {
@include box-sizing(border-box);
box-sizing: border-box;
overflow-x: hidden;
overflow-y: auto;
}

View File

@ -371,7 +371,9 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $mdP
content = strContent;
}
} else {
content = defaultContent(key, value);
var decimals = (contentInfo.decimals || contentInfo.decimals === 0) ? contentInfo.decimals : vm.widgetConfig.decimals;
var units = contentInfo.units || vm.widgetConfig.units;
content = vm.ctx.utils.formatValue(value, decimals, units, true);
}
return content;
} else {
@ -379,14 +381,6 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $mdP
}
}
function defaultContent(key, value) {
if (angular.isDefined(value)) {
return value;
} else {
return '';
}
}
function defaultStyle(/*key, value*/) {
return {};
}
@ -542,7 +536,9 @@ function EntitiesTableWidgetController($element, $scope, $filter, $mdMedia, $mdP
vm.contentsInfo[dataKey.label] = {
useCellContentFunction: useCellContentFunction,
cellContentFunction: cellContentFunction
cellContentFunction: cellContentFunction,
units: dataKey.units,
decimals: dataKey.decimals
};
var columnWidth = angular.isDefined(keySettings.columnWidth) ? keySettings.columnWidth : '0px';

View File

@ -333,6 +333,7 @@ export default class TbFlot {
lineWidth: 0,
fill: 0.9
}
ctx.defaultBarWidth = settings.defaultBarWidth || 600;
}
if (this.chartType === 'state') {
@ -476,7 +477,11 @@ export default class TbFlot {
this.options.yaxes = angular.copy(this.yaxes);
if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'state') {
if (this.chartType === 'bar') {
this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
if (this.subscription.timeWindowConfig.aggregation && this.subscription.timeWindowConfig.aggregation.type === 'NONE') {
this.options.series.bars.barWidth = this.ctx.defaultBarWidth;
} else {
this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
}
}
this.options.xaxis.min = this.subscription.timeWindow.minTime;
this.options.xaxis.max = this.subscription.timeWindow.maxTime;
@ -594,7 +599,11 @@ export default class TbFlot {
this.options.xaxis.min = this.subscription.timeWindow.minTime;
this.options.xaxis.max = this.subscription.timeWindow.maxTime;
if (this.chartType === 'bar') {
this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
if (this.subscription.timeWindowConfig.aggregation && this.subscription.timeWindowConfig.aggregation.type === 'NONE') {
this.options.series.bars.barWidth = this.ctx.defaultBarWidth;
} else {
this.options.series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
}
}
if (axisVisibilityChanged) {
@ -603,7 +612,11 @@ export default class TbFlot {
this.ctx.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime;
this.ctx.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime;
if (this.chartType === 'bar') {
this.ctx.plot.getOptions().series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
if (this.subscription.timeWindowConfig.aggregation && this.subscription.timeWindowConfig.aggregation.type === 'NONE') {
this.ctx.plot.getOptions().series.bars.barWidth = this.ctx.defaultBarWidth;
} else {
this.ctx.plot.getOptions().series.bars.barWidth = this.subscription.timeWindow.interval * 0.6;
}
}
this.updateData();
}
@ -810,238 +823,257 @@ export default class TbFlot {
}
}
static get settingsSchema() {
return {
static settingsSchema(chartType) {
var schema = {
"schema": {
"type": "object",
"title": "Settings",
"properties": {
"stack": {
"title": "Stacking",
"type": "boolean",
"default": false
},
"smoothLines": {
"title": "Display smooth (curved) lines",
"type": "boolean",
"default": false
},
"shadowSize": {
"title": "Shadow size",
"type": "number",
"default": 4
},
"fontColor": {
"title": "Font color",
}
}
};
var properties = schema["schema"]["properties"];
properties["stack"] = {
"title": "Stacking",
"type": "boolean",
"default": false
};
if (chartType === 'graph') {
properties["smoothLines"] = {
"title": "Display smooth (curved) lines",
"type": "boolean",
"default": false
};
}
if (chartType === 'bar') {
properties["defaultBarWidth"] = {
"title": "Default bar width for non-aggregated data (milliseconds)",
"type": "number",
"default": 600
};
}
properties["shadowSize"] = {
"title": "Shadow size",
"type": "number",
"default": 4
};
properties["fontColor"] = {
"title": "Font color",
"type": "string",
"default": "#545454"
};
properties["fontSize"] = {
"title": "Font size",
"type": "number",
"default": 10
};
properties["tooltipIndividual"] = {
"title": "Hover individual points",
"type": "boolean",
"default": false
};
properties["tooltipCumulative"] = {
"title": "Show cumulative values in stacking mode",
"type": "boolean",
"default": false
};
properties["tooltipValueFormatter"] = {
"title": "Tooltip value format function, f(value)",
"type": "string",
"default": ""
};
properties["grid"] = {
"title": "Grid settings",
"type": "object",
"properties": {
"color": {
"title": "Primary color",
"type": "string",
"default": "#545454"
},
"fontSize": {
"title": "Font size",
"type": "number",
"default": 10
},
"tooltipIndividual": {
"title": "Hover individual points",
"type": "boolean",
"default": false
},
"tooltipCumulative": {
"title": "Show cumulative values in stacking mode",
"type": "boolean",
"default": false
},
"tooltipValueFormatter": {
"title": "Tooltip value format function, f(value)",
"type": "string",
"default": ""
},
"grid": {
"title": "Grid settings",
"type": "object",
"properties": {
"color": {
"title": "Primary color",
"type": "string",
"default": "#545454"
},
"backgroundColor": {
"title": "Background color",
"type": "string",
"default": null
},
"tickColor": {
"title": "Ticks color",
"type": "string",
"default": "#DDDDDD"
},
"outlineWidth": {
"title": "Grid outline/border width (px)",
"type": "number",
"default": 1
},
"verticalLines": {
"title": "Show vertical lines",
"type": "boolean",
"default": true
},
"horizontalLines": {
"title": "Show horizontal lines",
"type": "boolean",
"default": true
}
}
},
"xaxis": {
"title": "X axis settings",
"type": "object",
"properties": {
"showLabels": {
"title": "Show labels",
"type": "boolean",
"default": true
},
"title": {
"title": "Axis title",
"type": "string",
"default": null
},
"titleAngle": {
"title": "Axis title's angle in degrees",
"type": "number",
"default": 0
},
"color": {
"title": "Ticks color",
"type": "string",
"default": null
}
}
},
"yaxis": {
"title": "Y axis settings",
"type": "object",
"properties": {
"min": {
"title": "Minimum value on the scale",
"type": "number",
"default": null
},
"max": {
"title": "Maximum value on the scale",
"type": "number",
"default": null
},
"showLabels": {
"title": "Show labels",
"type": "boolean",
"default": true
},
"title": {
"title": "Axis title",
"type": "string",
"default": null
},
"titleAngle": {
"title": "Axis title's angle in degrees",
"type": "number",
"default": 0
},
"color": {
"title": "Ticks color",
"type": "string",
"default": null
},
"ticksFormatter": {
"title": "Ticks formatter function, f(value)",
"type": "string",
"default": ""
},
"tickDecimals": {
"title": "The number of decimals to display",
"type": "number",
"default": 0
},
"tickSize": {
"title": "Step size between ticks",
"type": "number",
"default": null
}
}
}
},
"required": []
},
"form": [
"stack",
"smoothLines",
"shadowSize",
"backgroundColor": {
"title": "Background color",
"type": "string",
"default": null
},
"tickColor": {
"title": "Ticks color",
"type": "string",
"default": "#DDDDDD"
},
"outlineWidth": {
"title": "Grid outline/border width (px)",
"type": "number",
"default": 1
},
"verticalLines": {
"title": "Show vertical lines",
"type": "boolean",
"default": true
},
"horizontalLines": {
"title": "Show horizontal lines",
"type": "boolean",
"default": true
}
}
};
properties["xaxis"] = {
"title": "X axis settings",
"type": "object",
"properties": {
"showLabels": {
"title": "Show labels",
"type": "boolean",
"default": true
},
"title": {
"title": "Axis title",
"type": "string",
"default": null
},
"titleAngle": {
"title": "Axis title's angle in degrees",
"type": "number",
"default": 0
},
"color": {
"title": "Ticks color",
"type": "string",
"default": null
}
}
};
properties["yaxis"] = {
"title": "Y axis settings",
"type": "object",
"properties": {
"min": {
"title": "Minimum value on the scale",
"type": "number",
"default": null
},
"max": {
"title": "Maximum value on the scale",
"type": "number",
"default": null
},
"showLabels": {
"title": "Show labels",
"type": "boolean",
"default": true
},
"title": {
"title": "Axis title",
"type": "string",
"default": null
},
"titleAngle": {
"title": "Axis title's angle in degrees",
"type": "number",
"default": 0
},
"color": {
"title": "Ticks color",
"type": "string",
"default": null
},
"ticksFormatter": {
"title": "Ticks formatter function, f(value)",
"type": "string",
"default": ""
},
"tickDecimals": {
"title": "The number of decimals to display",
"type": "number",
"default": 0
},
"tickSize": {
"title": "Step size between ticks",
"type": "number",
"default": null
}
}
};
schema["schema"]["required"] = [];
schema["form"] = ["stack"];
if (chartType === 'graph') {
schema["form"].push("smoothLines");
}
if (chartType === 'bar') {
schema["form"].push("defaultBarWidth");
}
schema["form"].push("shadowSize");
schema["form"].push({
"key": "fontColor",
"type": "color"
});
schema["form"].push("fontSize");
schema["form"].push("tooltipIndividual");
schema["form"].push("tooltipCumulative");
schema["form"].push({
"key": "tooltipValueFormatter",
"type": "javascript"
});
schema["form"].push({
"key": "grid",
"items": [
{
"key": "fontColor",
"key": "grid.color",
"type": "color"
},
"fontSize",
"tooltipIndividual",
"tooltipCumulative",
{
"key": "tooltipValueFormatter",
"type": "javascript"
"key": "grid.backgroundColor",
"type": "color"
},
{
"key": "grid",
"items": [
{
"key": "grid.color",
"type": "color"
},
{
"key": "grid.backgroundColor",
"type": "color"
},
{
"key": "grid.tickColor",
"type": "color"
},
"grid.outlineWidth",
"grid.verticalLines",
"grid.horizontalLines"
]
"key": "grid.tickColor",
"type": "color"
},
{
"key": "xaxis",
"items": [
"xaxis.showLabels",
"xaxis.title",
"xaxis.titleAngle",
{
"key": "xaxis.color",
"type": "color"
}
]
},
{
"key": "yaxis",
"items": [
"yaxis.min",
"yaxis.max",
"yaxis.tickDecimals",
"yaxis.tickSize",
"yaxis.showLabels",
"yaxis.title",
"yaxis.titleAngle",
{
"key": "yaxis.color",
"type": "color"
},
{
"key": "yaxis.ticksFormatter",
"type": "javascript"
}
]
}
"grid.outlineWidth",
"grid.verticalLines",
"grid.horizontalLines"
]
}
});
schema["form"].push({
"key": "xaxis",
"items": [
"xaxis.showLabels",
"xaxis.title",
"xaxis.titleAngle",
{
"key": "xaxis.color",
"type": "color"
}
]
});
schema["form"].push({
"key": "yaxis",
"items": [
"yaxis.min",
"yaxis.max",
"yaxis.tickDecimals",
"yaxis.tickSize",
"yaxis.showLabels",
"yaxis.title",
"yaxis.titleAngle",
{
"key": "yaxis.color",
"type": "color"
},
{
"key": "yaxis.ticksFormatter",
"type": "javascript"
}
]
});
return schema;
}
static get pieDatakeySettingsSchema() {

View File

@ -37,8 +37,6 @@ $background-color: #e6e7e8 !default;
position: relative;
&[draggable] {
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}

View File

@ -60,19 +60,11 @@ $background-color: #e6e7e8 !default;
.led {
position: relative;
cursor: pointer;
background-image: -owg-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, .25));
background-image: -webkit-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, .25));
background-image: -moz-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, .25));
background-image: -o-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, .25));
background-image: radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, .25));
border-radius: 50%;
transition: background-color .5s, box-shadow .5s;
&.disabled {
background-image: -owg-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, .5), rgba(0, 0, 0, .1));
background-image: -webkit-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, .5), rgba(0, 0, 0, .1));
background-image: -moz-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, .5), rgba(0, 0, 0, .1));
background-image: -o-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, .5), rgba(0, 0, 0, .1));
background-image: radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, .5), rgba(0, 0, 0, .1));
}
}

View File

@ -59,6 +59,8 @@ $background-color: #e6e7e8 !default;
.switch {
position: relative;
box-sizing: border-box;
width: 260px;
min-width: 260px;
height: 260px;
@ -69,21 +71,14 @@ $background-color: #e6e7e8 !default;
color: #424242;
cursor: pointer;
-pie-background: -pie-linear-gradient(270deg, #bbb, #ddd);
background: #ddd;
background: -owg-linear-gradient(270deg, #bbb, #ddd);
background: -webkit-linear-gradient(270deg, #bbb, #ddd);
background: -moz-linear-gradient(270deg, #bbb, #ddd);
background: -o-linear-gradient(270deg, #bbb, #ddd);
background: linear-gradient(180deg, #bbb, #ddd);
border-radius: 130px;
@include box-sizing(border-box);
@include box-shadow(
0 0 0 8px rgba(0,0,0,.1)
,0 0 3px 1px rgba(0,0,0,.1)
,inset 0 8px 3px -8px rgba(255,255,255,.4));
box-shadow:
0 0 0 8px rgba(0, 0, 0, .1),
0 0 3px 1px rgba(0, 0, 0, .1),
inset 0 8px 3px -8px rgba(255, 255, 255, .4);
input {
display: none;
@ -95,7 +90,7 @@ $background-color: #e6e7e8 !default;
width: 100%;
text-align: center;
@include text-shadow(1px 1px 4px #4a4a4a);
text-shadow: 1px 1px 4px #4a4a4a;
}
.on {
@ -103,15 +98,15 @@ $background-color: #e6e7e8 !default;
font-family: sans-serif;
color: #444;
@include transition(all .1s);
transition: all .1s;
}
.off {
bottom: 5px;
@include transition(all .1s);
transition: all .1s;
@include transform(scaleY(.85));
transform: scaleY(.85);
}
.but {
@ -125,90 +120,82 @@ $background-color: #e6e7e8 !default;
border-bottom-width: 0;
border-radius: 400px 400px 400px 400px / 400px 400px 300px 300px;
@include box-shadow(inset 8px 6px 5px -7px #a2a2a2,
inset -8px 6px 5px -7px #a2a2a2,
inset 0 -3px 2px -2px rgba(200, 200, 200, .5),
0 3px 3px -2px #fff,
inset 0 -230px 60px -200px rgba(255, 255, 255, .2),
inset 0 220px 40px -200px rgba(0, 0, 0, .3));
box-shadow:
inset 8px 6px 5px -7px #a2a2a2,
inset -8px 6px 5px -7px #a2a2a2,
inset 0 -3px 2px -2px rgba(200, 200, 200, .5),
0 3px 3px -2px #fff,
inset 0 -230px 60px -200px rgba(255, 255, 255, .2),
inset 0 220px 40px -200px rgba(0, 0, 0, .3);
@include transition(all .2s);
transition: all .2s;
}
.back {
box-sizing: border-box;
width: 210px;
height: 210px;
padding: 4px 4px;
cursor: pointer;
background-color: #888787;
background-image: -owg-linear-gradient(0deg, transparent 30%, transparent 70%), -owg-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, .2) 50%, rgba(150, 150, 150, 0) 70%);
background-image: -webkit-linear-gradient(0deg, transparent 30%, transparent 70%), -webkit-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, .2) 50%, rgba(150, 150, 150, 0) 70%);
background-image: -moz-linear-gradient(0deg, transparent 30%, transparent 70%), -moz-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, .2) 50%, rgba(150, 150, 150, 0) 70%);
background-image: -o-linear-gradient(0deg, transparent 30%, transparent 70%), -o-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, .2) 50%, rgba(150, 150, 150, 0) 70%);
background-image: linear-gradient(-90deg, transparent 30%, transparent 70%), linear-gradient(0deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, .2) 50%, rgba(150, 150, 150, 0) 70%);
border-radius: 105px;
@include box-shadow(30px 30px 30px -20px rgba(58, 58, 58, .3),
-30px 30px 30px -20px rgba(58, 58, 58, .3),
0 30px 30px 0 rgba(16, 16, 16, .3),
inset 0 -1px 0 0 #484848);
box-shadow:
30px 30px 30px -20px rgba(58, 58, 58, .3),
-30px 30px 30px -20px rgba(58, 58, 58, .3),
0 30px 30px 0 rgba(16, 16, 16, .3),
inset 0 -1px 0 0 #484848;
@include box-sizing(border-box);
@include transition(all .2s);
transition: all .2s;
}
input:checked + .back .on,
input:checked + .back .off{
@include text-shadow(1px 1px 4px #4a4a4a);
text-shadow: 1px 1px 4px #4a4a4a;
}
input:checked + .back .on{
top: 10px;
color: #4c4c4c;
@include transform(scaleY(.85));
transform: scaleY(.85);
}
input:checked + .back .off{
bottom: 5px;
color: #444;
@include transform(scaleY(1));
transform: scaleY(1);
}
input:checked + .back .but{
margin-top: 20px;
background: #dcdcdc;
background-image: -owg-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, .3), transparent);
background-image: -webkit-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, .3), transparent);
background-image: -moz-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, .3), transparent);
background-image: -o-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, .3), transparent);
background-image: radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, .3), transparent);
border-radius: 400px 400px 400px 400px / 300px 300px 400px 400px;
@include box-shadow(inset 8px -4px 5px -7px #a9a9a9,
inset -8px -4px 5px -7px #808080,
0 -3px 8px -4px rgba(50, 50, 50, .4),
inset 0 3px 4px -2px #9c9c9c,
inset 0 280px 40px -200px rgba(0, 0, 0, .2),
inset 0 -200px 40px -200px rgba(180, 180, 180, .2));
box-shadow:
inset 8px -4px 5px -7px #a9a9a9,
inset -8px -4px 5px -7px #808080,
0 -3px 8px -4px rgba(50, 50, 50, .4),
inset 0 3px 4px -2px #9c9c9c,
inset 0 280px 40px -200px rgba(0, 0, 0, .2),
inset 0 -200px 40px -200px rgba(180, 180, 180, .2);
}
input:checked + .back{
padding: 2px 4px;
background-image: -owg-linear-gradient(90deg, #868686 30%, transparent 70%), -owg-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, .74) 50%, rgba(105, 105, 105, 0) 100%);
background-image: -webkit-linear-gradient(90deg, #868686 30%, transparent 70%), -webkit-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, .74) 50%, rgba(105, 105, 105, 0) 100%);
background-image: -moz-linear-gradient(90deg, #868686 30%, transparent 70%), -moz-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, .74) 50%, rgba(105, 105, 105, 0) 100%);
background-image: -o-linear-gradient(90deg, #868686 30%, transparent 70%), -o-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, .74) 50%, rgba(105, 105, 105, 0) 100%);
background-image: linear-gradient(0deg, #868686 30%, transparent 70%), linear-gradient(90deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, .74) 50%, rgba(105, 105, 105, 0) 100%);
@include box-shadow(30px 30px 30px -20px rgba(49, 49, 49, .1),
-30px 30px 30px -20px rgba(111, 111, 111, .1),
0 30px 30px 0 rgba(0, 0, 0, .2),
inset 0 1px 2px 0 rgba(167, 167, 167, .6));
box-shadow:
30px 30px 30px -20px rgba(49, 49, 49, .1),
-30px 30px 30px -20px rgba(111, 111, 111, .1),
0 30px 30px 0 rgba(0, 0, 0, .2),
inset 0 1px 2px 0 rgba(167, 167, 167, .6);
}
}
}

View File

@ -217,7 +217,9 @@ function TimeseriesTableWidgetController($element, $scope, $filter, $timeout) {
content = strContent;
}
} else {
content = vm.ctx.utils.formatValue(value, contentInfo.decimals, contentInfo.units);
var decimals = (contentInfo.decimals || contentInfo.decimals === 0) ? contentInfo.decimals : vm.widgetConfig.decimals;
var units = contentInfo.units || vm.widgetConfig.units;
content = vm.ctx.utils.formatValue(value, decimals, units, true);
}
return content;
}

View File

@ -19,7 +19,7 @@ $edit-toolbar-height: 40px !default;
.tb-editor {
.tb-split {
@include box-sizing(border-box);
box-sizing: border-box;
overflow-x: hidden;
overflow-y: auto;
}

View File

@ -15,34 +15,34 @@
*/
@import "~compass-sass-mixins/lib/animate";
@include keyframes(tbMoveFromTopFade) {
@keyframes tbMoveFromTopFade {
from {
opacity: 0;
@include transform(translate(0, -100%));
transform: translate(0, -100%);
}
}
@include keyframes(tbMoveToTopFade) {
@keyframes tbMoveToTopFade {
to {
opacity: 0;
@include transform(translate(0, -100%));
transform: translate(0, -100%);
}
}
@include keyframes(tbMoveFromBottomFade) {
@keyframes tbMoveFromBottomFade {
from {
opacity: 0;
@include transform(translate(0, 100%));
transform: translate(0, 100%);
}
}
@include keyframes(tbMoveToBottomFade) {
@keyframes tbMoveToBottomFade {
to {
opacity: 0;
@include transform(translate(0, 150%));
transform: translate(0, 150%);
}
}

View File

@ -42,7 +42,7 @@ textarea {
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-feature-settings: "liga";
-webkit-font-feature-settings: "liga"; /* stylelint-disable-line property-no-vendor-prefix */
}
a {
@ -51,7 +51,7 @@ a {
text-decoration: none;
border-bottom: 1px solid rgba(64, 84, 178, .25);
@include transition(border-bottom .35s);
transition: border-bottom .35s;
}
a:hover,
@ -258,13 +258,7 @@ label {
}
.tb-noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome and Opera */
user-select: none;
}
.tb-readonly-label {
@ -556,7 +550,7 @@ $previewSize: 100px !default;
}
.tb-error-message.ng-animate {
@include transition(all .3s cubic-bezier(.55, 0, .55, .2));
transition: all .3s cubic-bezier(.55, 0, .55, .2);
}
.tb-error-message.ng-enter-prepare,
@ -652,13 +646,13 @@ section.tb-top-header-buttons {
}
.tb-header-buttons .tb-btn-header {
@include animation(tbMoveFromTopFade .3s ease both);
position: relative !important;
display: inline-block !important;
animation: tbMoveFromTopFade .3s ease both;
}
.tb-header-buttons .tb-btn-header.ng-hide {
@include animation(tbMoveToTopFade .3s ease both);
animation: tbMoveToTopFade .3s ease both;
}
/***********************
@ -669,24 +663,24 @@ section.tb-footer-buttons {
position: fixed;
right: 20px;
bottom: 20px;
z-index: 13;
z-index: 30;
pointer-events: none;
}
.tb-footer-buttons .tb-btn-footer {
@include animation(tbMoveFromBottomFade .3s ease both);
position: relative !important;
display: inline-block !important;
animation: tbMoveFromBottomFade .3s ease both;
}
.tb-footer-buttons .tb-btn-footer.ng-hide {
@include animation(tbMoveToBottomFade .3s ease both);
animation: tbMoveToBottomFade .3s ease both;
}
._md-toast-open-bottom .tb-footer-buttons {
@include transition(all .4s cubic-bezier(.25, .8, .25, 1));
transition: all .4s cubic-bezier(.25, .8, .25, 1);
@include transform(translate3d(0, -42px, 0));
transform: translate3d(0, -42px, 0);
}
/***********************

View File

@ -15,6 +15,7 @@
*/
@import "~compass-sass-mixins/lib/compass";
/* stylelint-disable selector-no-vendor-prefix */
@mixin input-placeholder {
// replaces compass/css/user-interface/input-placeholder()
@ -36,6 +37,7 @@
@content;
}
}
/* stylelint-enable selector-no-vendor-prefix */
@mixin line-clamp($numLines: 1, $lineHeight: 1.412) {
position: relative;