TB-39: UI: Add Gateway flag. (#44)
* TB-39: UI: Add Gateway flag. * TB-39: UI: Update package version.
This commit is contained in:
parent
31b248922e
commit
7c6cdb148c
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "thingsboard",
|
"name": "thingsboard",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"description": "Thingsboard UI",
|
"description": "Thingsboard UI",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -52,6 +52,11 @@ const apiProxy = httpProxy.createProxyServer({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
apiProxy.on('error', function (err, req, res) {
|
||||||
|
console.warn('API proxy error: ' + err);
|
||||||
|
res.end('Error.');
|
||||||
|
});
|
||||||
|
|
||||||
console.info(`Forwarding API requests to http://${forwardHost}:${forwardPort}`);
|
console.info(`Forwarding API requests to http://${forwardHost}:${forwardPort}`);
|
||||||
|
|
||||||
app.all('/api/*', (req, res) => {
|
app.all('/api/*', (req, res) => {
|
||||||
|
|||||||
@ -256,6 +256,9 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
type: types.dataKeyType.timeseries,
|
type: types.dataKeyType.timeseries,
|
||||||
onData: function (data) {
|
onData: function (data) {
|
||||||
onData(data, types.dataKeyType.timeseries);
|
onData(data, types.dataKeyType.timeseries);
|
||||||
|
},
|
||||||
|
onReconnected: function() {
|
||||||
|
onReconnected();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,6 +281,9 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
type: types.dataKeyType.timeseries,
|
type: types.dataKeyType.timeseries,
|
||||||
onData: function (data) {
|
onData: function (data) {
|
||||||
onData(data, types.dataKeyType.timeseries);
|
onData(data, types.dataKeyType.timeseries);
|
||||||
|
},
|
||||||
|
onReconnected: function() {
|
||||||
|
onReconnected();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -299,6 +305,9 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
type: types.dataKeyType.attribute,
|
type: types.dataKeyType.attribute,
|
||||||
onData: function (data) {
|
onData: function (data) {
|
||||||
onData(data, types.dataKeyType.attribute);
|
onData(data, types.dataKeyType.attribute);
|
||||||
|
},
|
||||||
|
onReconnected: function() {
|
||||||
|
onReconnected();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -428,6 +437,25 @@ function DatasourceSubscription(datasourceSubscription, telemetryWebsocketServic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onReconnected() {
|
||||||
|
if (datasourceType === types.datasourceType.device) {
|
||||||
|
for (var key in dataKeys) {
|
||||||
|
var dataKeysList = dataKeys[key];
|
||||||
|
for (var i = 0; i < dataKeysList.length; i++) {
|
||||||
|
var dataKey = dataKeysList[i];
|
||||||
|
var datasourceKey = key + '_' + i;
|
||||||
|
datasourceData[datasourceKey] = [];
|
||||||
|
for (var l in listeners) {
|
||||||
|
var listener = listeners[l];
|
||||||
|
listener.dataUpdated(datasourceData[datasourceKey],
|
||||||
|
listener.datasourceIndex,
|
||||||
|
dataKey.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onData(sourceData, type) {
|
function onData(sourceData, type) {
|
||||||
for (var keyName in sourceData) {
|
for (var keyName in sourceData) {
|
||||||
var keyData = sourceData[keyName];
|
var keyData = sourceData[keyName];
|
||||||
|
|||||||
@ -307,12 +307,12 @@ function DeviceService($http, $q, $filter, telemetryWebsocketService, types) {
|
|||||||
onSubscriptionData(data, subscriptionId);
|
onSubscriptionData(data, subscriptionId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
telemetryWebsocketService.subscribe(subscriber);
|
|
||||||
deviceAttributesSubscription = {
|
deviceAttributesSubscription = {
|
||||||
subscriber: subscriber,
|
subscriber: subscriber,
|
||||||
attributes: null
|
attributes: null
|
||||||
}
|
}
|
||||||
deviceAttributesSubscriptionMap[subscriptionId] = deviceAttributesSubscription;
|
deviceAttributesSubscriptionMap[subscriptionId] = deviceAttributesSubscription;
|
||||||
|
telemetryWebsocketService.subscribe(subscriber);
|
||||||
}
|
}
|
||||||
return subscriptionId;
|
return subscriptionId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,11 +20,17 @@ export default angular.module('thingsboard.api.telemetryWebsocket', [thingsboard
|
|||||||
.factory('telemetryWebsocketService', TelemetryWebsocketService)
|
.factory('telemetryWebsocketService', TelemetryWebsocketService)
|
||||||
.name;
|
.name;
|
||||||
|
|
||||||
|
const RECONNECT_INTERVAL = 5000;
|
||||||
|
const WS_IDLE_TIMEOUT = 90000;
|
||||||
|
|
||||||
/*@ngInject*/
|
/*@ngInject*/
|
||||||
function TelemetryWebsocketService($websocket, $timeout, $window, types, userService) {
|
function TelemetryWebsocketService($rootScope, $websocket, $timeout, $window, types, userService) {
|
||||||
|
|
||||||
var isOpening = false,
|
var isOpening = false,
|
||||||
isOpened = false,
|
isOpened = false,
|
||||||
|
isActive = false,
|
||||||
|
isReconnect = false,
|
||||||
|
reconnectSubscribers = [],
|
||||||
lastCmdId = 0,
|
lastCmdId = 0,
|
||||||
subscribers = {},
|
subscribers = {},
|
||||||
subscribersCount = 0,
|
subscribersCount = 0,
|
||||||
@ -36,7 +42,8 @@ function TelemetryWebsocketService($websocket, $timeout, $window, types, userSer
|
|||||||
telemetryUri,
|
telemetryUri,
|
||||||
dataStream,
|
dataStream,
|
||||||
location = $window.location,
|
location = $window.location,
|
||||||
socketCloseTimer;
|
socketCloseTimer,
|
||||||
|
reconnectTimer;
|
||||||
|
|
||||||
if (location.protocol === "https:") {
|
if (location.protocol === "https:") {
|
||||||
telemetryUri = "wss:";
|
telemetryUri = "wss:";
|
||||||
@ -46,11 +53,18 @@ function TelemetryWebsocketService($websocket, $timeout, $window, types, userSer
|
|||||||
telemetryUri += "//" + location.hostname + ":" + location.port;
|
telemetryUri += "//" + location.hostname + ":" + location.port;
|
||||||
telemetryUri += "/api/ws/plugins/telemetry";
|
telemetryUri += "/api/ws/plugins/telemetry";
|
||||||
|
|
||||||
|
|
||||||
var service = {
|
var service = {
|
||||||
subscribe: subscribe,
|
subscribe: subscribe,
|
||||||
unsubscribe: unsubscribe
|
unsubscribe: unsubscribe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rootScope.telemetryWsLogoutHandle = $rootScope.$on('unauthenticated', function (event, doLogout) {
|
||||||
|
if (doLogout) {
|
||||||
|
reset(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return service;
|
return service;
|
||||||
|
|
||||||
function publishCommands () {
|
function publishCommands () {
|
||||||
@ -74,12 +88,42 @@ function TelemetryWebsocketService($websocket, $timeout, $window, types, userSer
|
|||||||
function onOpen () {
|
function onOpen () {
|
||||||
isOpening = false;
|
isOpening = false;
|
||||||
isOpened = true;
|
isOpened = true;
|
||||||
|
if (reconnectTimer) {
|
||||||
|
$timeout.cancel(reconnectTimer);
|
||||||
|
reconnectTimer = null;
|
||||||
|
}
|
||||||
|
if (isReconnect) {
|
||||||
|
isReconnect = false;
|
||||||
|
for (var r in reconnectSubscribers) {
|
||||||
|
var reconnectSubscriber = reconnectSubscribers[r];
|
||||||
|
if (reconnectSubscriber.onReconnected) {
|
||||||
|
reconnectSubscriber.onReconnected();
|
||||||
|
}
|
||||||
|
subscribe(reconnectSubscriber);
|
||||||
|
}
|
||||||
|
reconnectSubscribers = [];
|
||||||
|
} else {
|
||||||
publishCommands();
|
publishCommands();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onClose () {
|
function onClose () {
|
||||||
isOpening = false;
|
isOpening = false;
|
||||||
isOpened = false;
|
isOpened = false;
|
||||||
|
if (isActive) {
|
||||||
|
if (!isReconnect) {
|
||||||
|
reconnectSubscribers = [];
|
||||||
|
for (var id in subscribers) {
|
||||||
|
reconnectSubscribers.push(subscribers[id]);
|
||||||
|
}
|
||||||
|
reset(false);
|
||||||
|
isReconnect = true;
|
||||||
|
}
|
||||||
|
if (reconnectTimer) {
|
||||||
|
$timeout.cancel(reconnectTimer);
|
||||||
|
}
|
||||||
|
reconnectTimer = $timeout(tryOpenSocket, RECONNECT_INTERVAL, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMessage (message) {
|
function onMessage (message) {
|
||||||
@ -137,28 +181,60 @@ function TelemetryWebsocketService($websocket, $timeout, $window, types, userSer
|
|||||||
function checkToClose () {
|
function checkToClose () {
|
||||||
if (subscribersCount === 0 && isOpened) {
|
if (subscribersCount === 0 && isOpened) {
|
||||||
if (!socketCloseTimer) {
|
if (!socketCloseTimer) {
|
||||||
socketCloseTimer = $timeout(closeSocket, 90000, false);
|
socketCloseTimer = $timeout(closeSocket, WS_IDLE_TIMEOUT, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryOpenSocket () {
|
function tryOpenSocket () {
|
||||||
|
isActive = true;
|
||||||
if (!isOpened && !isOpening) {
|
if (!isOpened && !isOpening) {
|
||||||
isOpening = true;
|
isOpening = true;
|
||||||
dataStream = $websocket(telemetryUri + '?token=' + userService.getJwtToken());
|
if (userService.isJwtTokenValid()) {
|
||||||
|
openSocket(userService.getJwtToken());
|
||||||
|
} else {
|
||||||
|
userService.refreshJwtToken().then(function success() {
|
||||||
|
openSocket(userService.getJwtToken());
|
||||||
|
}, function fail() {
|
||||||
|
isOpening = false;
|
||||||
|
$rootScope.$broadcast('unauthenticated');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (socketCloseTimer) {
|
||||||
|
$timeout.cancel(socketCloseTimer);
|
||||||
|
socketCloseTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSocket(token) {
|
||||||
|
dataStream = $websocket(telemetryUri + '?token=' + token);
|
||||||
dataStream.onError(onError);
|
dataStream.onError(onError);
|
||||||
dataStream.onOpen(onOpen);
|
dataStream.onOpen(onOpen);
|
||||||
dataStream.onClose(onClose);
|
dataStream.onClose(onClose);
|
||||||
dataStream.onMessage(onMessage);
|
dataStream.onMessage(onMessage);
|
||||||
}
|
}
|
||||||
if (socketCloseTimer) {
|
|
||||||
$timeout.cancel(socketCloseTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeSocket() {
|
function closeSocket() {
|
||||||
|
isActive = false;
|
||||||
if (isOpened) {
|
if (isOpened) {
|
||||||
dataStream.close();
|
dataStream.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reset(closeSocket) {
|
||||||
|
if (socketCloseTimer) {
|
||||||
|
$timeout.cancel(socketCloseTimer);
|
||||||
|
socketCloseTimer = null;
|
||||||
|
}
|
||||||
|
lastCmdId = 0;
|
||||||
|
subscribers = {};
|
||||||
|
subscribersCount = 0;
|
||||||
|
cmdsWrapper.tsSubCmds = [];
|
||||||
|
cmdsWrapper.historyCmds = [];
|
||||||
|
cmdsWrapper.attrSubCmds = [];
|
||||||
|
if (closeSocket) {
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,6 +147,12 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
|
|||||||
scope.subscriptionId = newSubscriptionId;
|
scope.subscriptionId = newSubscriptionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope.$on('$destroy', function() {
|
||||||
|
if (scope.subscriptionId) {
|
||||||
|
deviceService.unsubscribeForDeviceAttributes(scope.subscriptionId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
scope.editAttribute = function($event, attribute) {
|
scope.editAttribute = function($event, attribute) {
|
||||||
if (!scope.attributeScope.clientSide) {
|
if (!scope.attributeScope.clientSide) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
|
|||||||
@ -59,6 +59,11 @@
|
|||||||
<div translate ng-message="required">device.name-required</div>
|
<div translate ng-message="required">device.name-required</div>
|
||||||
</div>
|
</div>
|
||||||
</md-input-container>
|
</md-input-container>
|
||||||
|
<md-input-container class="md-block">
|
||||||
|
<md-checkbox ng-disabled="loading || !isEdit" flex aria-label="{{ 'device.is-gateway' | translate }}"
|
||||||
|
ng-model="device.additionalInfo.gateway">{{ 'device.is-gateway' | translate }}
|
||||||
|
</md-checkbox>
|
||||||
|
</md-input-container>
|
||||||
<md-input-container class="md-block">
|
<md-input-container class="md-block">
|
||||||
<label translate>device.description</label>
|
<label translate>device.description</label>
|
||||||
<textarea ng-model="device.additionalInfo.description" rows="2"></textarea>
|
<textarea ng-model="device.additionalInfo.description" rows="2"></textarea>
|
||||||
|
|||||||
@ -32,11 +32,13 @@ export default function DeviceDirective($compile, $templateCache, toast, $transl
|
|||||||
|
|
||||||
scope.$watch('device', function(newVal) {
|
scope.$watch('device', function(newVal) {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
|
if (scope.device.id) {
|
||||||
deviceService.getDeviceCredentials(scope.device.id.id).then(
|
deviceService.getDeviceCredentials(scope.device.id.id).then(
|
||||||
function success(credentials) {
|
function success(credentials) {
|
||||||
scope.deviceCredentials = credentials;
|
scope.deviceCredentials = credentials;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
if (scope.device.customerId && scope.device.customerId.id !== types.id.nullUid) {
|
if (scope.device.customerId && scope.device.customerId.id !== types.id.nullUid) {
|
||||||
scope.isAssignedToCustomer = true;
|
scope.isAssignedToCustomer = true;
|
||||||
customerService.getCustomer(scope.device.customerId.id).then(
|
customerService.getCustomer(scope.device.customerId.id).then(
|
||||||
|
|||||||
@ -323,7 +323,8 @@
|
|||||||
"accessTokenCopiedMessage": "Device access token has been copied to clipboard",
|
"accessTokenCopiedMessage": "Device access token has been copied to clipboard",
|
||||||
"assignedToCustomer": "Assigned to customer",
|
"assignedToCustomer": "Assigned to customer",
|
||||||
"unable-delete-device-alias-title": "Unable to delete device alias",
|
"unable-delete-device-alias-title": "Unable to delete device alias",
|
||||||
"unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}"
|
"unable-delete-device-alias-text": "Device alias '{{deviceAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}",
|
||||||
|
"is-gateway": "Is gateway"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"close": "Close dialog"
|
"close": "Close dialog"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user