Commit d965df8c271f0569b02908ea486922e18465543a

Authored by Andrii Shvaika
2 parents 283ad27c eab6ba45

Merge remote-tracking branch 'origin/master' into develop/2.5

@@ -6,6 +6,38 @@ @@ -6,6 +6,38 @@
6 }, 6 },
7 "widgetTypes": [ 7 "widgetTypes": [
8 { 8 {
  9 + "alias": "attributes_card",
  10 + "name": "Gateway events",
  11 + "descriptor": {
  12 + "type": "latest",
  13 + "sizeX": 7.5,
  14 + "sizeY": 8,
  15 + "resources": [],
  16 + "templateHtml": "",
  17 + "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
  18 + "controllerScript": "let types;\nlet eventsReg = \"eventsReg\";\n\nself.onInit = function() {\n \n self.ctx.datasourceTitleCells = [];\n self.ctx.valueCells = [];\n self.ctx.labelCells = [];\n types = self.ctx.$scope.$injector.get('types');\n \n if (self.ctx.datasources.length && self.ctx.datasources[0].type === types.datasourceType.entity) {\n getDatasourceKeys(self.ctx.datasources[0]);\n } else {\n processDatasources(self.ctx.datasources);\n }\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.valueCells.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData && cellData.data && cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var textValue;\n //toDo -> + IsNumber\n \n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (cellData.dataKey.decimals || cellData.dataKey.decimals === 0) {\n decimals = cellData.dataKey.decimals;\n }\n if (cellData.dataKey.units) {\n units = cellData.dataKey.units;\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, false);\n }\n else {\n txtValue = value;\n }\n self.ctx.valueCells[i].html(txtValue);\n }\n }\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n}\n\nself.onResize = function() {\n var datasourceTitleFontSize = self.ctx.height/8;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n datasourceTitleFontSize = self.ctx.width/12;\n }\n datasourceTitleFontSize = Math.min(datasourceTitleFontSize, 20);\n for (var i = 0; i < self.ctx.datasourceTitleCells.length; i++) {\n self.ctx.datasourceTitleCells[i].css('font-size', datasourceTitleFontSize+'px');\n }\n var valueFontSize = self.ctx.height/9;\n var labelFontSize = self.ctx.height/9;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n valueFontSize = self.ctx.width/15;\n labelFontSize = self.ctx.width/15;\n }\n valueFontSize = Math.min(valueFontSize, 18);\n labelFontSize = Math.min(labelFontSize, 18);\n\n for (i = 0; i < self.ctx.valueCells; i++) {\n self.ctx.valueCells[i].css('font-size', valueFontSize+'px');\n self.ctx.valueCells[i].css('height', valueFontSize*2.5+'px');\n self.ctx.valueCells[i].css('padding', '0px ' + valueFontSize + 'px');\n self.ctx.labelCells[i].css('font-size', labelFontSize+'px');\n self.ctx.labelCells[i].css('height', labelFontSize*2.5+'px');\n self.ctx.labelCells[i].css('padding', '0px ' + labelFontSize + 'px');\n } \n}\n\nfunction processDatasources(datasources) {\n var i = 0;\n var tbDatasource = datasources[i];\n var datasourceId = 'tbDatasource' + i;\n self.ctx.$container.append(\n \"<div id='\" + datasourceId +\n \"' class='tbDatasource-container'></div>\"\n );\n\n var datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n\n datasourceContainer.append(\n \"<div class='tbDatasource-title'>\" +\n tbDatasource.name + \"</div>\"\n );\n \n var datasourceTitleCell = $('.tbDatasource-title', datasourceContainer);\n self.ctx.datasourceTitleCells.push(datasourceTitleCell);\n \n var tableId = 'table' + i;\n datasourceContainer.append(\n \"<table id='\" + tableId +\n \"' class='tbDatasource-table'><col width='30%'><col width='70%'></table>\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n\n for (var a = 0; a < tbDatasource.dataKeys.length; a++) {\n var dataKey = tbDatasource.dataKeys[a];\n var labelCellId = 'labelCell' + a;\n var cellId = 'cell' + a;\n table.append(\"<tr><td id='\" + labelCellId + \"'>\" + dataKey.label +\n \"</td><td id='\" + cellId +\n \"'></td></tr>\");\n var labelCell = $('#' + labelCellId, table);\n self.ctx.labelCells.push(labelCell);\n var valueCell = $('#' + cellId, table);\n self.ctx.valueCells.push(valueCell);\n }\n self.onResize();\n}\n\nfunction getDatasourceKeys (datasource) {\n let attributeService = self.ctx.$scope.$injector.get('attributeService');\n if (datasource.entityId && datasource.entityType) {\n attributeService.getEntityKeys(datasource.entityType, datasource.entityId, \"\" , types.dataKeyType.timeseries).then(\n function(data){\n if (data.length) {\n subscribeForKeys (datasource, data);\n }\n });\n }\n}\n\nfunction subscribeForKeys (datasource, data) {\n let eventsRegVals = self.ctx.settings[eventsReg];\n if (eventsRegVals && eventsRegVals.length > 0) {\n var dataKeys = [];\n data.sort();\n data.forEach(dataValue => {eventsRegVals.forEach(event => {\n if (dataValue.toLowerCase().includes(event.toLowerCase())) {\n var dataKey = {\n type: types.dataKeyType.timeseries,\n name: dataValue,\n label: dataValue,\n settings: {},\n _hash: Math.random()\n };\n dataKeys.push(dataKey);\n }\n })});\n\n if (dataKeys.length) {\n updateSubscription (datasource, dataKeys);\n }\n }\n}\n\nfunction updateSubscription (datasource, dataKeys) {\n var datasources = [\n {\n type: types.datasourceType.entity,\n name: datasource.aliasName,\n aliasName: datasource.aliasName,\n entityAliasId: datasource.entityAliasId,\n dataKeys: dataKeys\n }\n ];\n \n var subscriptionOptions = {\n datasources: datasources,\n useDashboardTimewindow: false,\n type: types.widgetType.latest.value,\n callbacks: {\n onDataUpdated: (subscription) => {\n self.ctx.data = subscription.data;\n self.onDataUpdated();\n }\n }\n };\n \n processDatasources(datasources);\n self.ctx.subscriptionApi.createSubscription(subscriptionOptions, true).then(\n (subscription) => {\n self.ctx.defaultSubscription = subscription;\n }\n );\n}\n\nself.onDestroy = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\t\n dataKeysOptional: true\n };\n}\n\n",
  19 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"GatewayEventsForm\",\n \"properties\": {\n \"eventsTitle\": {\n \"title\": \"Gateway events form title\",\n \"type\": \"string\",\n \"default\": \"Gateway Events Form\"\n },\n \"eventsReg\": {\n \"title\": \"Events filten.\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Event key contains\",\n \"type\": \"string\"\n }\n }\n }\n },\n \"form\": [\n \"eventsTitle\",\n \"eventsReg\"\n ]\n}",
  20 + "dataKeySettingsSchema": "{}\n",
  21 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Function Math.round\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.826503672916844,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"eventsTitle\":\"Gateway Events Form\",\"eventsReg\":[]},\"title\":\"Gateway events\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
  22 + }
  23 + },
  24 + {
  25 + "alias": "config_form_latest",
  26 + "name": "Gateway configuration (Single device)",
  27 + "descriptor": {
  28 + "type": "latest",
  29 + "sizeX": 7.5,
  30 + "sizeY": 9,
  31 + "resources": [],
  32 + "templateHtml": "<tb-gateway-form\n form-id=\"formId\"\n ctx=\"ctx\"\n is-state-form=\"isStateForm\">\n</tb-gateway-form>",
  33 + "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}",
  34 + "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.formId = \"form-\"+id;\n scope.ctx = self.ctx;\n scope.isStateForm = true;\n}\n\nself.onResize = function() {\n self.ctx.$scope.$broadcast('gateway-form-resize', self.ctx.$scope.formId);\n}\n\n\nself.onDestroy = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\t\t\t\n dataKeysOptional: true\t\t\n };\n}\n\n",
  35 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"GatewayConfigForm\",\n \"properties\": {\n \"gatewayTitle\": {\n \"title\": \"Gateway form\",\n \"type\": \"string\",\n \"default\": \"Gateway configuration (Single device)\"\n },\n \"readOnly\": {\n \"title\": \"Read Only\",\n \"type\": \"boolean\",\n \"default\": false\n }\n }\n },\n \"form\": [\n \"gatewayTitle\",\n \"readOnly\"\n ]\n}\n",
  36 + "dataKeySettingsSchema": "{}\n",
  37 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"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\":{},\"title\":\"Gateway configuration (Single device)\"}"
  38 + }
  39 + },
  40 + {
9 "alias": "extension_configuration_widget", 41 "alias": "extension_configuration_widget",
10 "name": "Extensions table", 42 "name": "Extensions table",
11 "descriptor": { 43 "descriptor": {
@@ -1645,7 +1645,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { @@ -1645,7 +1645,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
1645 addPageLinkToParam(params, pageLink); 1645 addPageLinkToParam(params, pageLink);
1646 1646
1647 Map<String, List<JsonNode>> timeseries = restTemplate.exchange( 1647 Map<String, List<JsonNode>> timeseries = restTemplate.exchange(
1648 - baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&interval={interval}&agg={agg}&useStrictDataTypes={useStrictDataTypes}&" + getUrlParams(pageLink), 1648 + baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&interval={interval}&agg={agg}&useStrictDataTypes={useStrictDataTypes}&" + getUrlParamsTs(pageLink),
1649 HttpMethod.GET, 1649 HttpMethod.GET,
1650 HttpEntity.EMPTY, 1650 HttpEntity.EMPTY,
1651 new ParameterizedTypeReference<Map<String, List<JsonNode>>>() { 1651 new ParameterizedTypeReference<Map<String, List<JsonNode>>>() {
@@ -1997,12 +1997,20 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable { @@ -1997,12 +1997,20 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
1997 } 1997 }
1998 1998
1999 private String getUrlParams(TimePageLink pageLink) { 1999 private String getUrlParams(TimePageLink pageLink) {
  2000 + return getUrlParams(pageLink, "startTime", "endTime");
  2001 + }
  2002 +
  2003 + private String getUrlParamsTs(TimePageLink pageLink) {
  2004 + return getUrlParams(pageLink, "startTs", "endTs");
  2005 + }
  2006 +
  2007 + private String getUrlParams(TimePageLink pageLink, String startTime, String endTime) {
2000 String urlParams = "limit={limit}&ascOrder={ascOrder}"; 2008 String urlParams = "limit={limit}&ascOrder={ascOrder}";
2001 if (pageLink.getStartTime() != null) { 2009 if (pageLink.getStartTime() != null) {
2002 - urlParams += "&startTime={startTime}"; 2010 + urlParams += "&" + startTime + "={startTime}";
2003 } 2011 }
2004 if (pageLink.getEndTime() != null) { 2012 if (pageLink.getEndTime() != null) {
2005 - urlParams += "&endTime={endTime}"; 2013 + urlParams += "&" + endTime + "={endTime}";
2006 } 2014 }
2007 if (pageLink.getIdOffset() != null) { 2015 if (pageLink.getIdOffset() != null) {
2008 urlParams += "&offset={offset}"; 2016 urlParams += "&offset={offset}";
@@ -606,13 +606,29 @@ export default angular.module('thingsboard.types', []) @@ -606,13 +606,29 @@ export default angular.module('thingsboard.types', [])
606 value: "modbus", 606 value: "modbus",
607 name: "Modbus" 607 name: "Modbus"
608 }, 608 },
609 - opc_ua: { 609 + opcua: {
610 value: "opcua", 610 value: "opcua",
611 name: "OPC-UA" 611 name: "OPC-UA"
612 }, 612 },
613 ble: { 613 ble: {
614 value: "ble", 614 value: "ble",
615 name: "BLE" 615 name: "BLE"
  616 + },
  617 + request: {
  618 + value: "request",
  619 + name: "Request"
  620 + },
  621 + can: {
  622 + value: "can",
  623 + name: "CAN"
  624 + },
  625 + bacnet: {
  626 + value: "bacnet",
  627 + name: "BACnet"
  628 + },
  629 + custom: {
  630 + value: "custom",
  631 + name: "Custom"
616 } 632 }
617 }, 633 },
618 gatewayLogLevel: { 634 gatewayLogLevel: {
@@ -37,7 +37,8 @@ function GatewayConfig() { @@ -37,7 +37,8 @@ function GatewayConfig() {
37 disabled: '=ngDisabled', 37 disabled: '=ngDisabled',
38 gatewayConfig: '=', 38 gatewayConfig: '=',
39 changeAlignment: '=', 39 changeAlignment: '=',
40 - theForm: '=' 40 + theForm: '=',
  41 + isReadOnly: '='
41 }, 42 },
42 controller: GatewayConfigController, 43 controller: GatewayConfigController,
43 controllerAs: 'vm', 44 controllerAs: 'vm',
@@ -83,6 +84,10 @@ function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window, @@ -83,6 +84,10 @@ function GatewayConfigController($scope, $document, $mdDialog, $mdUtil, $window,
83 multiple: true, 84 multiple: true,
84 }).then(function (config) { 85 }).then(function (config) {
85 if (config && index > -1) { 86 if (config && index > -1) {
  87 + console.log(config); //eslint-disable-line
  88 + if (!angular.equals(vm.gatewayConfig[index].config, config)) {
  89 + $scope.gatewayConfiguration.$setDirty();
  90 + }
86 vm.gatewayConfig[index].config = config; 91 vm.gatewayConfig[index].config = config;
87 } 92 }
88 }); 93 });
@@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
18 <section name="gatewayConfig" layout="column" class="gateway-config"> 18 <section name="gatewayConfig" layout="column" class="gateway-config">
19 <section layout="row" ng-form="gatewayConfig_{{$index}}" ng-repeat="connector in vm.gatewayConfig track by $index"> 19 <section layout="row" ng-form="gatewayConfig_{{$index}}" ng-repeat="connector in vm.gatewayConfig track by $index">
20 <div layout="column" layout-align="center start" class="gateway-config-row"> 20 <div layout="column" layout-align="center start" class="gateway-config-row">
21 - <md-switch ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)" 21 + <md-switch ng-disabled="vm.isReadOnly" ng-model="connector.enabled" ng-disabled="gatewayConfig_{{$index}}.$invalid || vm.validateJSON(connector.config)"
22 aria-label="{{ 'gateway.connector-enabled' | translate }}"> 22 aria-label="{{ 'gateway.connector-enabled' | translate }}">
23 </md-switch> 23 </md-switch>
24 </div> 24 </div>
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> 26 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
27 <md-input-container class="md-block" flex> 27 <md-input-container class="md-block" flex>
28 <label>{{'gateway.connector-type' | translate }}</label> 28 <label>{{'gateway.connector-type' | translate }}</label>
29 - <md-select name="connectorType" 29 + <md-select ng-disabled="vm.isReadOnly" name="connectorType"
30 ng-change="vm.changeConnectorType(connector)" 30 ng-change="vm.changeConnectorType(connector)"
31 aria-label="{{ 'gateway.gateway.connector-type' | translate }}" 31 aria-label="{{ 'gateway.gateway.connector-type' | translate }}"
32 ng-model="connector.configType" required> 32 ng-model="connector.configType" required>
@@ -39,7 +39,7 @@ @@ -39,7 +39,7 @@
39 </div> 39 </div>
40 </md-input-container> 40 </md-input-container>
41 <md-input-container class="md-block" flex> 41 <md-input-container class="md-block" flex>
42 - <input placeholder="{{'gateway.connector-name' | translate }}" 42 + <input ng-disabled="vm.isReadOnly" placeholder="{{'gateway.connector-name' | translate }}"
43 ng-model-options="{ updateOn: 'blur' }" 43 ng-model-options="{ updateOn: 'blur' }"
44 ng-change="vm.changeConnectorName(connector, $index)" name="connectorName" ng-model="connector.name" required/> 44 ng-change="vm.changeConnectorName(connector, $index)" name="connectorName" ng-model="connector.name" required/>
45 <div ng-messages="vm.theForm.connectorName.$error"> 45 <div ng-messages="vm.theForm.connectorName.$error">
@@ -49,7 +49,7 @@ @@ -49,7 +49,7 @@
49 </div> 49 </div>
50 <div layout="row" layout-align="end center" class="action-buttons" 50 <div layout="row" layout-align="end center" class="action-buttons"
51 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> 51 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
52 - <md-button class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)" 52 + <md-button ng-disabled="vm.isReadOnly" class="md-icon-button md-mini" ng-click="vm.openConfigDialog($event, $index, connector.config, connector.name)"
53 aria-label="{{ 'gateway.update-config' | translate }}" 53 aria-label="{{ 'gateway.update-config' | translate }}"
54 ng-class="{'md-warn': vm.validateJSON(connector.config)}"> 54 ng-class="{'md-warn': vm.validateJSON(connector.config)}">
55 <md-icon class="material-icons">more_horiz</md-icon> 55 <md-icon class="material-icons">more_horiz</md-icon>
@@ -57,7 +57,7 @@ @@ -57,7 +57,7 @@
57 {{ 'gateway.update-config' | translate }} 57 {{ 'gateway.update-config' | translate }}
58 </md-tooltip> 58 </md-tooltip>
59 </md-button> 59 </md-button>
60 - <md-button class="md-icon-button md-mini" ng-click="vm.removeConnector($index)" 60 + <md-button ng-disabled="vm.isReadOnly" class="md-icon-button md-mini" ng-click="vm.removeConnector($index)"
61 aria-label="{{ 'gateway.delete' | translate }}"> 61 aria-label="{{ 'gateway.delete' | translate }}">
62 <md-icon class="material-icons">close</md-icon> 62 <md-icon class="material-icons">close</md-icon>
63 <md-tooltip md-direction="top"> 63 <md-tooltip md-direction="top">
@@ -70,7 +70,7 @@ @@ -70,7 +70,7 @@
70 layout-align="center center" ng-class="{'disabled': vm.disabled}" 70 layout-align="center center" ng-class="{'disabled': vm.disabled}"
71 class="no-data-found" translate>{{'gateway.no-connectors'}}</span> 71 class="no-data-found" translate>{{'gateway.no-connectors'}}</span>
72 <div> 72 <div>
73 - <md-button class="md-raised" ng-click="vm.addNewConnector()" 73 + <md-button ng-show="!vm.isReadOnly" class="md-raised" ng-click="vm.addNewConnector()"
74 aria-label="{{ 'gateway.connector-add' | translate }}"> 74 aria-label="{{ 'gateway.connector-add' | translate }}">
75 <md-tooltip md-direction="top"> 75 <md-tooltip md-direction="top">
76 {{ 'gateway.connector-add' | translate }} 76 {{ 'gateway.connector-add' | translate }}
@@ -31,11 +31,15 @@ function GatewayForm() { @@ -31,11 +31,15 @@ function GatewayForm() {
31 scope: true, 31 scope: true,
32 bindToController: { 32 bindToController: {
33 formId: '=', 33 formId: '=',
34 - ctx: '=' 34 + ctx: '=',
  35 + isStateForm: '=',
  36 + deviceName: '=',
  37 + isReadOnly: '=',
  38 + isState: '='
35 }, 39 },
36 controller: GatewayFormController, 40 controller: GatewayFormController,
37 controllerAs: 'vm', 41 controllerAs: 'vm',
38 - templateUrl: gatewayFormTemplate 42 + templateUrl: gatewayFormTemplate,
39 }; 43 };
40 } 44 }
41 45
@@ -47,10 +51,11 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -47,10 +51,11 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
47 const configurationAttribute = "configuration"; 51 const configurationAttribute = "configuration";
48 const remoteLoggingLevelAttribute = "RemoteLoggingLevel"; 52 const remoteLoggingLevelAttribute = "RemoteLoggingLevel";
49 53
50 - const templateLogsConfig = '[loggers]}}keys=root, service, connector, converter, tb_connection, storage, extension}}[handlers]}}keys=consoleHandler, serviceHandler, connectorHandler, converterHandler, tb_connectionHandler, storageHandler, extensionHandler}}[formatters]}}keys=LogFormatter}}[logger_root]}}level=ERROR}}handlers=consoleHandler}}[logger_connector]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=connector}}[logger_storage]}}level={ERROR}}}handlers=storageHandler}}formatter=LogFormatter}}qualname=storage}}[logger_tb_connection]}}level={ERROR}}}handlers=tb_connectionHandler}}formatter=LogFormatter}}qualname=tb_connection}}[logger_service]}}level={ERROR}}}handlers=serviceHandler}}formatter=LogFormatter}}qualname=service}}[logger_converter]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=converter}}[logger_extension]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=extension}}[handler_consoleHandler]}}class=StreamHandler}}level={ERROR}}}formatter=LogFormatter}}args=(sys.stdout,)}}[handler_connectorHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}connector.log", "d", 1, 7,)}}[handler_storageHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}storage.log", "d", 1, 7,)}}[handler_serviceHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}service.log", "d", 1, 7,)}}[handler_converterHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}converter.log", "d", 1, 3,)}}[handler_extensionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}extension.log", "d", 1, 3,)}}[handler_tb_connectionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}tb_connection.log", "d", 1, 3,)}}[formatter_LogFormatter]}}format="%(asctime)s - %(levelname)s - [%(filename)s] - %(module)s - %(lineno)d - %(message)s" }}datefmt="%Y-%m-%d %H:%M:%S"'; 54 + const templateLogsConfig = '[loggers]}}keys=root, service, connector, converter, tb_connection, storage, extension}}[handlers]}}keys=consoleHandler, serviceHandler, connectorHandler, converterHandler, tb_connectionHandler, storageHandler, extensionHandler}}[formatters]}}keys=LogFormatter}}[logger_root]}}level=ERROR}}handlers=consoleHandler}}[logger_connector]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=connector}}[logger_storage]}}level={ERROR}}}handlers=storageHandler}}formatter=LogFormatter}}qualname=storage}}[logger_tb_connection]}}level={ERROR}}}handlers=tb_connectionHandler}}formatter=LogFormatter}}qualname=tb_connection}}[logger_service]}}level={ERROR}}}handlers=serviceHandler}}formatter=LogFormatter}}qualname=service}}[logger_converter]}}level={ERROR}}}handlers=converterHandler}}formatter=LogFormatter}}qualname=converter}}[logger_extension]}}level={ERROR}}}handlers=connectorHandler}}formatter=LogFormatter}}qualname=extension}}[handler_consoleHandler]}}class=StreamHandler}}level={ERROR}}}formatter=LogFormatter}}args=(sys.stdout,)}}[handler_connectorHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}connector.log", "d", 1, 7,)}}[handler_storageHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}storage.log", "d", 1, 7,)}}[handler_serviceHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}service.log", "d", 1, 7,)}}[handler_converterHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}converter.log", "d", 1, 3,)}}[handler_extensionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}extension.log", "d", 1, 3,)}}[handler_tb_connectionHandler]}}level={ERROR}}}class=logging.handlers.TimedRotatingFileHandler}}formatter=LogFormatter}}args=("{./logs/}tb_connection.log", "d", 1, 3,)}}[formatter_LogFormatter]}}format="%(asctime)s - %(levelname)s - [%(filename)s] - %(module)s - %(lineno)d - %(message)s" }}datefmt="%Y-%m-%d %H:%M:%S"';
51 55
52 vm.types = types; 56 vm.types = types;
53 - 57 + vm.deviceNameForm = (vm.deviceName) ? vm.deviceName : null;
  58 + vm.idForm = Math.random().toString(36).replace(/^0\.[0-9]*/, '');
54 vm.configurations = { 59 vm.configurations = {
55 gateway: '', 60 gateway: '',
56 host: $document[0].domain, 61 host: $document[0].domain,
@@ -74,7 +79,6 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -74,7 +79,6 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
74 let archiveFileName = ''; 79 let archiveFileName = '';
75 let gatewayNameExists = ''; 80 let gatewayNameExists = '';
76 let successfulSaved = ''; 81 let successfulSaved = '';
77 -  
78 vm.securityTypes = [{ 82 vm.securityTypes = [{
79 name: 'gateway.security-types.access-token', 83 name: 'gateway.security-types.access-token',
80 value: 'accessToken' 84 value: 'accessToken'
@@ -92,13 +96,18 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -92,13 +96,18 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
92 }]; 96 }];
93 97
94 $scope.$watch('vm.ctx', function () { 98 $scope.$watch('vm.ctx', function () {
95 - if (vm.ctx ) { 99 + if (vm.ctx) {
  100 + vm.isStateForm = $scope.isStateForm;
96 vm.settings = vm.ctx.settings; 101 vm.settings = vm.ctx.settings;
97 vm.widgetConfig = vm.ctx.widgetConfig; 102 vm.widgetConfig = vm.ctx.widgetConfig;
98 - initializeConfig(); 103 + if (vm.ctx.datasources && vm.ctx.datasources.length) {
  104 + vm.deviceNameForm = vm.ctx.datasources[0].name;
  105 + }
99 } 106 }
  107 + initializeConfig();
100 }); 108 });
101 109
  110 +
102 $scope.$on('gateway-form-resize', function (event, formId) { 111 $scope.$on('gateway-form-resize', function (event, formId) {
103 if (vm.formId == formId) { 112 if (vm.formId == formId) {
104 updateWidgetDisplaying(); 113 updateWidgetDisplaying();
@@ -106,21 +115,34 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -106,21 +115,34 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
106 }); 115 });
107 116
108 function updateWidgetDisplaying() { 117 function updateWidgetDisplaying() {
109 - vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425); 118 + if (vm.ctx) {
  119 + vm.changeAlignment = (vm.ctx.$container[0].offsetWidth <= 425);
  120 + }
110 } 121 }
111 122
112 function initWidgetSettings() { 123 function initWidgetSettings() {
113 let widgetTitle; 124 let widgetTitle;
114 - if (vm.settings.widgetTitle && vm.settings.widgetTitle.length) {  
115 - widgetTitle = utils.customTranslation(vm.settings.widgetTitle, vm.settings.widgetTitle); 125 + if (vm.settings) {
  126 + vm.isReadOnlyForm = (vm.settings.readOnly) ? vm.settings.readOnly : false;
  127 + if (vm.settings.gatewayTitle && vm.settings.gatewayTitle.length) {
  128 + widgetTitle = utils.customTranslation(vm.settings.gatewayTitle, vm.settings.gatewayTitle);
  129 + }
116 } else { 130 } else {
  131 + vm.isReadOnlyForm = false;
117 widgetTitle = $translate.instant('gateway.gateway'); 132 widgetTitle = $translate.instant('gateway.gateway');
118 } 133 }
119 - vm.ctx.widgetTitle = widgetTitle; 134 + if (vm.ctx) {
  135 + vm.ctx.widgetTitle = widgetTitle;
  136 + }
120 137
121 - archiveFileName = vm.settings.archiveFileName && vm.settings.archiveFileName.length ? vm.settings.archiveFileName : 'gatewayConfiguration';  
122 - gatewayNameExists = utils.customTranslation(vm.settings.gatewayNameExists, vm.settings.gatewayNameExists) || $translate.instant('gateway.gateway-exists');  
123 - successfulSaved = utils.customTranslation(vm.settings.successfulSave, vm.settings.successfulSave) || $translate.instant('gateway.gateway-saved'); 138 + archiveFileName = vm.settings && vm.settings.archiveFileName && vm.settings.archiveFileName.length ? vm.settings.archiveFileName : 'gatewayConfiguration';
  139 + if (vm.settings) {
  140 + gatewayNameExists = utils.customTranslation(vm.settings.deviceNameExist, vm.settings.deviceNameExist) || $translate.instant('gateway.gateway-exists');
  141 + successfulSaved = utils.customTranslation(vm.settings.successfulSave, vm.settings.successfulSave) || $translate.instant('gateway.gateway-saved');
  142 + } else {
  143 + gatewayNameExists = $translate.instant('gateway.gateway-exists');
  144 + successfulSaved = $translate.instant('gateway.gateway-saved');
  145 + }
124 } 146 }
125 147
126 function initializeConfig() { 148 function initializeConfig() {
@@ -129,6 +151,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -129,6 +151,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
129 getGatewaysList(true); 151 getGatewaysList(true);
130 } 152 }
131 153
  154 +
132 vm.getAccessToken = (deviceId) => { 155 vm.getAccessToken = (deviceId) => {
133 if (deviceId.id) { 156 if (deviceId.id) {
134 getDeviceCredentials(deviceId.id); 157 getDeviceCredentials(deviceId.id);
@@ -152,15 +175,15 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -152,15 +175,15 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
152 deviceService.findByName(deviceObj.name, {ignoreErrors: true}) 175 deviceService.findByName(deviceObj.name, {ignoreErrors: true})
153 .then( 176 .then(
154 function () { 177 function () {
155 - toast.showError(gatewayNameExists, angular.element('.gateway-form'),'top left'); 178 + toast.showError(gatewayNameExists, angular.element('.gateway-form'), 'top left');
156 }, 179 },
157 function () { 180 function () {
158 - if(vm.settings.gatewayType && vm.settings.gatewayType.length){ 181 + if (vm.settings.gatewayType && vm.settings.gatewayType.length) {
159 deviceObj.type = vm.settings.gatewayType; 182 deviceObj.type = vm.settings.gatewayType;
160 } 183 }
161 deviceService.saveDevice(deviceObj).then( 184 deviceService.saveDevice(deviceObj).then(
162 (device) => { 185 (device) => {
163 - getDeviceCredentials(device.id.id).then(() =>{ 186 + getDeviceCredentials(device.id.id).then(() => {
164 getGatewaysList(); 187 getGatewaysList();
165 }); 188 });
166 } 189 }
@@ -173,8 +196,8 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -173,8 +196,8 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
173 saveAttribute(configurationAttribute, $window.btoa(angular.toJson(getGatewayConfigJSON())), types.attributesScope.shared.value), 196 saveAttribute(configurationAttribute, $window.btoa(angular.toJson(getGatewayConfigJSON())), types.attributesScope.shared.value),
174 saveAttribute(configurationDraftsAttribute, $window.btoa(angular.toJson(getDraftConnectorJSON())), types.attributesScope.server.value), 197 saveAttribute(configurationDraftsAttribute, $window.btoa(angular.toJson(getDraftConnectorJSON())), types.attributesScope.server.value),
175 saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value) 198 saveAttribute(remoteLoggingLevelAttribute, vm.configurations.remoteLoggingLevel.toUpperCase(), types.attributesScope.shared.value)
176 - ]).then(() =>{  
177 - toast.showSuccess(successfulSaved, 2000, angular.element('.gateway-form'),'top left'); 199 + ]).then(() => {
  200 + toast.showSuccess(successfulSaved, 2000, angular.element('.gateway-form'), 'top left');
178 }) 201 })
179 }; 202 };
180 203
@@ -238,7 +261,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -238,7 +261,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
238 config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n'; 261 config += ' max_records_per_file: ' + vm.configurations.maxRecordsCount + '\n';
239 } 262 }
240 config += 'connectors:\n'; 263 config += 'connectors:\n';
241 - for(let i = 0; i < vm.configurations.connectors.length; i++){ 264 + for (let i = 0; i < vm.configurations.connectors.length; i++) {
242 if (vm.configurations.connectors[i].enabled) { 265 if (vm.configurations.connectors[i].enabled) {
243 config += ' -\n'; 266 config += ' -\n';
244 config += ' name: ' + vm.configurations.connectors[i].name + '\n'; 267 config += ' name: ' + vm.configurations.connectors[i].name + '\n';
@@ -250,7 +273,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -250,7 +273,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
250 } 273 }
251 274
252 function generateConfigConnectorFiles(fileZipAdd) { 275 function generateConfigConnectorFiles(fileZipAdd) {
253 - for(let i = 0; i < vm.configurations.connectors.length; i++){ 276 + for (let i = 0; i < vm.configurations.connectors.length; i++) {
254 if (vm.configurations.connectors[i].enabled) { 277 if (vm.configurations.connectors[i].enabled) {
255 fileZipAdd[generateFileName(vm.configurations.connectors[i].name)] = angular.toJson(vm.configurations.connectors[i].config); 278 fileZipAdd[generateFileName(vm.configurations.connectors[i].name)] = angular.toJson(vm.configurations.connectors[i].config);
256 } 279 }
@@ -276,7 +299,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -276,7 +299,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
276 299
277 function gatewayMainConfigJSON() { 300 function gatewayMainConfigJSON() {
278 let configuration = {}; 301 let configuration = {};
279 - 302 +
280 let thingsBoard = {}; 303 let thingsBoard = {};
281 thingsBoard.host = vm.configurations.host; 304 thingsBoard.host = vm.configurations.host;
282 thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration; 305 thingsBoard.remoteConfiguration = vm.configurations.remoteConfiguration;
@@ -325,10 +348,10 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -325,10 +348,10 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
325 } 348 }
326 349
327 function gatewayConnectorConfigJSON(gatewayConfiguration) { 350 function gatewayConnectorConfigJSON(gatewayConfiguration) {
328 - for(let i = 0; i < vm.configurations.connectors.length; i++){ 351 + for (let i = 0; i < vm.configurations.connectors.length; i++) {
329 if (vm.configurations.connectors[i].enabled) { 352 if (vm.configurations.connectors[i].enabled) {
330 let typeConnector = vm.configurations.connectors[i].configType; 353 let typeConnector = vm.configurations.connectors[i].configType;
331 - if(!angular.isArray(gatewayConfiguration[typeConnector])){ 354 + if (!angular.isArray(gatewayConfiguration[typeConnector])) {
332 gatewayConfiguration[typeConnector] = []; 355 gatewayConfiguration[typeConnector] = [];
333 } 356 }
334 357
@@ -343,7 +366,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -343,7 +366,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
343 366
344 function getDraftConnectorJSON() { 367 function getDraftConnectorJSON() {
345 let draftConnector = {}; 368 let draftConnector = {};
346 - for(let i = 0; i < vm.configurations.connectors.length; i++){ 369 + for (let i = 0; i < vm.configurations.connectors.length; i++) {
347 if (!vm.configurations.connectors[i].enabled) { 370 if (!vm.configurations.connectors[i].enabled) {
348 let connector = { 371 let connector = {
349 connector: vm.configurations.connectors[i].configType, 372 connector: vm.configurations.connectors[i].configType,
@@ -362,7 +385,10 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -362,7 +385,10 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
362 const device = devices[i]; 385 const device = devices[i];
363 if (device.additionalInfo !== null && device.additionalInfo.gateway === true) { 386 if (device.additionalInfo !== null && device.additionalInfo.gateway === true) {
364 vm.gateways.push(device); 387 vm.gateways.push(device);
365 - if (firstInit && vm.gateways.length && device.name === vm.gateways[0].name) { 388 + if (vm.deviceNameForm && firstInit && vm.gateways.length && device.name === vm.deviceNameForm) {
  389 + vm.configurations.gateway = device;
  390 + vm.getAccessToken(device.id);
  391 + } else if (firstInit && vm.gateways.length && device.name === vm.gateways[0].name) {
366 vm.configurations.gateway = device; 392 vm.configurations.gateway = device;
367 vm.getAccessToken(device.id); 393 vm.getAccessToken(device.id);
368 } 394 }
@@ -385,7 +411,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel, @@ -385,7 +411,7 @@ function GatewayFormController($scope, $injector, $document, $mdExpansionPanel,
385 for (let connectorType in keyValue) { 411 for (let connectorType in keyValue) {
386 let name = "No name"; 412 let name = "No name";
387 if (Object.prototype.hasOwnProperty.call(keyValue[connectorType], 'name')) { 413 if (Object.prototype.hasOwnProperty.call(keyValue[connectorType], 'name')) {
388 - name = keyValue[connectorType].name ; 414 + name = keyValue[connectorType].name;
389 } 415 }
390 let connector = { 416 let connector = {
391 enabled: true, 417 enabled: true,
@@ -17,30 +17,36 @@ @@ -17,30 +17,36 @@
17 --> 17 -->
18 <md-content md-scroll-y layout="column" class="gateway-form"> 18 <md-content md-scroll-y layout="column" class="gateway-form">
19 <form name="gatewayConfiguration"> 19 <form name="gatewayConfiguration">
20 - <md-expansion-panel-group>  
21 - <md-expansion-panel md-component-id="thingsboardPanelId"> 20 + <md-expansion-panel-group>
  21 + <md-expansion-panel md-component-id="{{vm.idForm}}thingsboardPanelId">
22 <md-expansion-panel-collapsed> 22 <md-expansion-panel-collapsed>
23 <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> 23 <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div>
24 <span flex></span> 24 <span flex></span>
25 <md-expansion-panel-icon></md-expansion-panel-icon> 25 <md-expansion-panel-icon></md-expansion-panel-icon>
26 </md-expansion-panel-collapsed> 26 </md-expansion-panel-collapsed>
27 <md-expansion-panel-expanded> 27 <md-expansion-panel-expanded>
28 - <md-expansion-panel-header ng-click="vm.collapsePanel('thingsboardPanelId')"> 28 + <md-expansion-panel-header ng-click="vm.collapsePanel(vm.idForm + 'thingsboardPanelId')">
29 <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div> 29 <div class="tb-panel-title">{{ 'gateway.thingsboard' | translate | uppercase }}</div>
30 <span flex></span> 30 <span flex></span>
31 <md-expansion-panel-icon></md-expansion-panel-icon> 31 <md-expansion-panel-icon></md-expansion-panel-icon>
32 </md-expansion-panel-header> 32 </md-expansion-panel-header>
33 <md-expansion-panel-content> 33 <md-expansion-panel-content>
34 - <tb-gateway-config-select tb-required="true" 34 + <tb-gateway-config-select ng-if="!vm.isStateForm"
  35 + tb-required="true"
35 ng-model="vm.configurations.gateway" 36 ng-model="vm.configurations.gateway"
36 the-form="gatewayConfiguration" 37 the-form="gatewayConfiguration"
37 gateway-list="vm.gateways" 38 gateway-list="vm.gateways"
38 get_access_token="vm.getAccessToken" 39 get_access_token="vm.getAccessToken"
39 create-device="vm.createDevice"> 40 create-device="vm.createDevice">
40 </tb-gateway-config-select> 41 </tb-gateway-config-select>
  42 + <md-input-container ng-if="vm.isStateForm"
  43 + class="md-block">
  44 + <label>{{'gateway.gateway-name' | translate }}</label>
  45 + <input ng-disabled="true" type="text" ng-model="vm.configurations.gateway.name" name="gatewayName"/>
  46 + </md-input-container>
41 <md-input-container class="md-block"> 47 <md-input-container class="md-block">
42 <label>{{'gateway.security-type' | translate }}</label> 48 <label>{{'gateway.security-type' | translate }}</label>
43 - <md-select name="securityType" ng-model="vm.configurations.securityType" required> 49 + <md-select ng-disabled="vm.isReadOnlyForm" name="securityType" ng-model="vm.configurations.securityType" required>
44 <md-option ng-repeat="securityType in vm.securityTypes" ng-value="securityType.value"> 50 <md-option ng-repeat="securityType in vm.securityTypes" ng-value="securityType.value">
45 {{securityType.name | translate}} 51 {{securityType.name | translate}}
46 </md-option> 52 </md-option>
@@ -50,14 +56,14 @@ @@ -50,14 +56,14 @@
50 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> 56 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
51 <md-input-container class="md-block" flex> 57 <md-input-container class="md-block" flex>
52 <label>{{ 'gateway.thingsboard-host' | translate }}</label> 58 <label>{{ 'gateway.thingsboard-host' | translate }}</label>
53 - <input type="text" name="host" ng-model="vm.configurations.host" required> 59 + <input ng-disabled="vm.isReadOnlyForm" type="text" name="host" ng-model="vm.configurations.host" required>
54 <div ng-messages="gatewayConfiguration.host.$error"> 60 <div ng-messages="gatewayConfiguration.host.$error">
55 <div ng-message="required" translate>gateway.thingsboard-host-required</div> 61 <div ng-message="required" translate>gateway.thingsboard-host-required</div>
56 </div> 62 </div>
57 </md-input-container> 63 </md-input-container>
58 <md-input-container class="md-block" flex> 64 <md-input-container class="md-block" flex>
59 <label>{{ 'gateway.thingsboard-port' | translate }}</label> 65 <label>{{ 'gateway.thingsboard-port' | translate }}</label>
60 - <input type="number" min="1" max="65535" ng-pattern="/^-?[0-9]+$/" name="port" 66 + <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" max="65535" ng-pattern="/^-?[0-9]+$/" name="port"
61 ng-model="vm.configurations.port" required> 67 ng-model="vm.configurations.port" required>
62 <div ng-messages="gatewayConfiguration.port.$error"> 68 <div ng-messages="gatewayConfiguration.port.$error">
63 <div ng-message="required" translate>gateway.thingsboard-port-required</div> 69 <div ng-message="required" translate>gateway.thingsboard-port-required</div>
@@ -70,18 +76,18 @@ @@ -70,18 +76,18 @@
70 <div ng-if="vm.configurations.securityType=='tls'"> 76 <div ng-if="vm.configurations.securityType=='tls'">
71 <md-input-container class="md-block security-type"> 77 <md-input-container class="md-block security-type">
72 <label>{{'gateway.tls-path-ca-certificate' | translate }}</label> 78 <label>{{'gateway.tls-path-ca-certificate' | translate }}</label>
73 - <input type="text" ng-model="vm.configurations.caCertPath" name="caCertPath" /> 79 + <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.caCertPath" name="caCertPath"/>
74 </md-input-container> 80 </md-input-container>
75 <md-input-container class="md-block"> 81 <md-input-container class="md-block">
76 <label>{{'gateway.tls-path-private-key' | translate }}</label> 82 <label>{{'gateway.tls-path-private-key' | translate }}</label>
77 - <input type="text" ng-model="vm.configurations.privateKeyPath" name="privateKeyPath" /> 83 + <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.privateKeyPath" name="privateKeyPath"/>
78 </md-input-container> 84 </md-input-container>
79 <md-input-container class="md-block"> 85 <md-input-container class="md-block">
80 <label>{{'gateway.tls-path-client-certificate' | translate }}</label> 86 <label>{{'gateway.tls-path-client-certificate' | translate }}</label>
81 - <input type="text" ng-model="vm.configurations.certPath" name="certPath" /> 87 + <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.certPath" name="certPath"/>
82 </md-input-container> 88 </md-input-container>
83 </div> 89 </div>
84 - <md-checkbox ng-model="vm.configurations.remoteConfiguration" 90 + <md-checkbox ng-show="!vm.isReadOnlyForm" ng-model="vm.configurations.remoteConfiguration"
85 name="remoteConfiguration" 91 name="remoteConfiguration"
86 aria-label="{{ 'gateway.remote-remote' | translate }}"> 92 aria-label="{{ 'gateway.remote-remote' | translate }}">
87 {{ 'gateway.remote' | translate }} 93 {{ 'gateway.remote' | translate }}
@@ -90,7 +96,7 @@ @@ -90,7 +96,7 @@
90 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> 96 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
91 <md-input-container class="md-block md-select-container" flex> 97 <md-input-container class="md-block md-select-container" flex>
92 <label>{{'gateway.remote-logging-level' | translate }}</label> 98 <label>{{'gateway.remote-logging-level' | translate }}</label>
93 - <md-select name="loggingLevel" ng-model="vm.configurations.remoteLoggingLevel"> 99 + <md-select ng-disabled="vm.isReadOnlyForm" name="loggingLevel" ng-model="vm.configurations.remoteLoggingLevel">
94 <md-option ng-repeat="logLevel in vm.types.gatewayLogLevel" 100 <md-option ng-repeat="logLevel in vm.types.gatewayLogLevel"
95 ng-value="logLevel" ng-selected="$index === 5"> 101 ng-value="logLevel" ng-selected="$index === 5">
96 {{logLevel}} 102 {{logLevel}}
@@ -99,7 +105,7 @@ @@ -99,7 +105,7 @@
99 </md-input-container> 105 </md-input-container>
100 <md-input-container class="md-block" flex> 106 <md-input-container class="md-block" flex>
101 <label>{{'gateway.path-logs' | translate }}</label> 107 <label>{{'gateway.path-logs' | translate }}</label>
102 - <input type="text" ng-model="vm.configurations.remoteLoggingPathToLogs" 108 + <input ng-disabled="vm.isReadOnlyForm" type="text" ng-model="vm.configurations.remoteLoggingPathToLogs"
103 name="remoteLoggingPathToLogs" required> 109 name="remoteLoggingPathToLogs" required>
104 <div ng-messages="gatewayConfiguration.remoteLoggingPathToLogs.$error"> 110 <div ng-messages="gatewayConfiguration.remoteLoggingPathToLogs.$error">
105 <div ng-message="required" translate>gateway.path-logs-required</div> 111 <div ng-message="required" translate>gateway.path-logs-required</div>
@@ -109,14 +115,14 @@ @@ -109,14 +115,14 @@
109 </md-expansion-panel-content> 115 </md-expansion-panel-content>
110 </md-expansion-panel-expanded> 116 </md-expansion-panel-expanded>
111 </md-expansion-panel> 117 </md-expansion-panel>
112 - <md-expansion-panel md-component-id="storagePanelId"> 118 + <md-expansion-panel md-component-id="{{vm.idForm}}storagePanelId">
113 <md-expansion-panel-collapsed> 119 <md-expansion-panel-collapsed>
114 <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> 120 <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div>
115 <span flex></span> 121 <span flex></span>
116 <md-expansion-panel-icon></md-expansion-panel-icon> 122 <md-expansion-panel-icon></md-expansion-panel-icon>
117 </md-expansion-panel-collapsed> 123 </md-expansion-panel-collapsed>
118 <md-expansion-panel-expanded> 124 <md-expansion-panel-expanded>
119 - <md-expansion-panel-header ng-click="vm.collapsePanel('storagePanelId')"> 125 + <md-expansion-panel-header ng-click="vm.collapsePanel(vm.idForm + 'storagePanelId')">
120 <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div> 126 <div class="tb-panel-title">{{ 'gateway.storage' | translate | uppercase }}</div>
121 <span flex></span> 127 <span flex></span>
122 <md-expansion-panel-icon></md-expansion-panel-icon> 128 <md-expansion-panel-icon></md-expansion-panel-icon>
@@ -124,18 +130,17 @@ @@ -124,18 +130,17 @@
124 <md-expansion-panel-content> 130 <md-expansion-panel-content>
125 <md-input-container class="md-block" flex> 131 <md-input-container class="md-block" flex>
126 <label>{{'gateway.storage-type' | translate }}</label> 132 <label>{{'gateway.storage-type' | translate }}</label>
127 - <md-select required ng-model="vm.configurations.storageType"> 133 + <md-select ng-disabled="vm.isReadOnlyForm" required ng-model="vm.configurations.storageType">
128 <md-option ng-repeat="storageType in vm.storageTypes" ng-value="storageType.value"> 134 <md-option ng-repeat="storageType in vm.storageTypes" ng-value="storageType.value">
129 {{storageType.name | translate}} 135 {{storageType.name | translate}}
130 </md-option> 136 </md-option>
131 </md-select> 137 </md-select>
132 </md-input-container> 138 </md-input-container>
133 -  
134 <div layout="row" class="gateway-form-row" 139 <div layout="row" class="gateway-form-row"
135 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> 140 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
136 <md-input-container class="md-block" flex> 141 <md-input-container class="md-block" flex>
137 <label>{{'gateway.storage-pack-size' | translate }}</label> 142 <label>{{'gateway.storage-pack-size' | translate }}</label>
138 - <input type="number" min="1" name="readRecordsCount" ng-pattern="/^-?[0-9]+$/" 143 + <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" name="readRecordsCount" ng-pattern="/^-?[0-9]+$/"
139 ng-model='vm.configurations.readRecordsCount' required/> 144 ng-model='vm.configurations.readRecordsCount' required/>
140 <div ng-messages="gatewayConfiguration.readRecordsCount.$error"> 145 <div ng-messages="gatewayConfiguration.readRecordsCount.$error">
141 <div ng-message="required" translate>gateway.storage-pack-size-required</div> 146 <div ng-message="required" translate>gateway.storage-pack-size-required</div>
@@ -143,10 +148,9 @@ @@ -143,10 +148,9 @@
143 <div ng-message="pattern" translate>gateway.storage-pack-size-pattern</div> 148 <div ng-message="pattern" translate>gateway.storage-pack-size-pattern</div>
144 </div> 149 </div>
145 </md-input-container> 150 </md-input-container>
146 -  
147 <md-input-container class="md-block" flex> 151 <md-input-container class="md-block" flex>
148 <label translate>{{ vm.configurations.storageType !== 'fileStorage' ? 'gateway.storage-max-records' : 'gateway.storage-max-file-records' }}</label> 152 <label translate>{{ vm.configurations.storageType !== 'fileStorage' ? 'gateway.storage-max-records' : 'gateway.storage-max-file-records' }}</label>
149 - <input type="number" min="1" name="maxRecordsCount" ng-pattern="/^-?[0-9]+$/" 153 + <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" name="maxRecordsCount" ng-pattern="/^-?[0-9]+$/"
150 ng-model='vm.configurations.maxRecordsCount' required/> 154 ng-model='vm.configurations.maxRecordsCount' required/>
151 <div ng-messages="gatewayConfiguration.maxRecordsCount.$error"> 155 <div ng-messages="gatewayConfiguration.maxRecordsCount.$error">
152 <div ng-message="required" translate>gateway.storage-max-records-required</div> 156 <div ng-message="required" translate>gateway.storage-max-records-required</div>
@@ -155,13 +159,12 @@ @@ -155,13 +159,12 @@
155 </div> 159 </div>
156 </md-input-container> 160 </md-input-container>
157 </div> 161 </div>
158 -  
159 <div layout="row" class="gateway-form-row" 162 <div layout="row" class="gateway-form-row"
160 ng-if="vm.configurations.storageType == 'fileStorage'" 163 ng-if="vm.configurations.storageType == 'fileStorage'"
161 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}"> 164 ng-class="{'gateway-config-row-vertical': vm.changeAlignment}">
162 <md-input-container class="md-block" flex> 165 <md-input-container class="md-block" flex>
163 <label>{{'gateway.storage-max-files' | translate }}</label> 166 <label>{{'gateway.storage-max-files' | translate }}</label>
164 - <input type="number" min="1" name="maxFilesCount" ng-pattern="/^-?[0-9]+$/" 167 + <input ng-disabled="vm.isReadOnlyForm" type="number" min="1" name="maxFilesCount" ng-pattern="/^-?[0-9]+$/"
165 ng-model='vm.configurations.maxFilesCount' required/> 168 ng-model='vm.configurations.maxFilesCount' required/>
166 <div ng-messages="gatewayConfiguration.maxFilesCount.$error"> 169 <div ng-messages="gatewayConfiguration.maxFilesCount.$error">
167 <div ng-message="required" translate>gateway.storage-max-files-required</div> 170 <div ng-message="required" translate>gateway.storage-max-files-required</div>
@@ -169,10 +172,9 @@ @@ -169,10 +172,9 @@
169 <div ng-message="pattern" translate>gateway.storage-max-files-pattern</div> 172 <div ng-message="pattern" translate>gateway.storage-max-files-pattern</div>
170 </div> 173 </div>
171 </md-input-container> 174 </md-input-container>
172 -  
173 <md-input-container class="md-block" flex> 175 <md-input-container class="md-block" flex>
174 <label>{{'gateway.storage-path' | translate }}</label> 176 <label>{{'gateway.storage-path' | translate }}</label>
175 - <input type="text" name="dataFolderPath" ng-model='vm.configurations.dataFolderPath' 177 + <input ng-disabled="vm.isReadOnlyForm" type="text" name="dataFolderPath" ng-model='vm.configurations.dataFolderPath'
176 required/> 178 required/>
177 <div ng-messages="gatewayConfiguration.dataFolderPath.$error"> 179 <div ng-messages="gatewayConfiguration.dataFolderPath.$error">
178 <div ng-message="required" translate>gateway.storage-path-required</div> 180 <div ng-message="required" translate>gateway.storage-path-required</div>
@@ -182,14 +184,14 @@ @@ -182,14 +184,14 @@
182 </md-expansion-panel-content> 184 </md-expansion-panel-content>
183 </md-expansion-panel-expanded> 185 </md-expansion-panel-expanded>
184 </md-expansion-panel> 186 </md-expansion-panel>
185 - <md-expansion-panel md-component-id="connectorsPanelId"> 187 + <md-expansion-panel md-component-id="{{vm.idForm}}connectorsPanelId">
186 <md-expansion-panel-collapsed> 188 <md-expansion-panel-collapsed>
187 <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> 189 <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div>
188 <span flex></span> 190 <span flex></span>
189 <md-expansion-panel-icon></md-expansion-panel-icon> 191 <md-expansion-panel-icon></md-expansion-panel-icon>
190 </md-expansion-panel-collapsed> 192 </md-expansion-panel-collapsed>
191 <md-expansion-panel-expanded> 193 <md-expansion-panel-expanded>
192 - <md-expansion-panel-header ng-click="vm.collapsePanel('connectorsPanelId')"> 194 + <md-expansion-panel-header ng-click="vm.collapsePanel(vm.idForm + 'connectorsPanelId')">
193 <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div> 195 <div class="tb-panel-title">{{ 'gateway.connectors' | translate | uppercase }}</div>
194 <span flex></span> 196 <span flex></span>
195 <md-expansion-panel-icon></md-expansion-panel-icon> 197 <md-expansion-panel-icon></md-expansion-panel-icon>
@@ -198,13 +200,14 @@ @@ -198,13 +200,14 @@
198 <tb-gateway-config 200 <tb-gateway-config
199 gateway-config="vm.configurations.connectors" 201 gateway-config="vm.configurations.connectors"
200 the-form="gatewayConfiguration" 202 the-form="gatewayConfiguration"
201 - change-alignment="vm.changeAlignment"> 203 + change-alignment="vm.changeAlignment"
  204 + is-read-only="vm.isReadOnlyForm">
202 </tb-gateway-config> 205 </tb-gateway-config>
203 </md-expansion-panel-content> 206 </md-expansion-panel-content>
204 </md-expansion-panel-expanded> 207 </md-expansion-panel-expanded>
205 </md-expansion-panel> 208 </md-expansion-panel>
206 </md-expansion-panel-group> 209 </md-expansion-panel-group>
207 - <section layout="row" layout-align="end center" class="form-action-buttons"> 210 + <section ng-show="!vm.isReadOnlyForm" layout="row" layout-align="end center" class="form-action-buttons">
208 <md-button class="md-primary md-raised" 211 <md-button class="md-primary md-raised"
209 ng-click="vm.exportConfig()" 212 ng-click="vm.exportConfig()"
210 ng-if="!vm.configurations.remoteConfiguration" 213 ng-if="!vm.configurations.remoteConfiguration"
@@ -213,14 +216,14 @@ @@ -213,14 +216,14 @@
213 {{'action.download' | translate }} 216 {{'action.download' | translate }}
214 <md-tooltip>{{'gateway.download-tip' | translate }}</md-tooltip> 217 <md-tooltip>{{'gateway.download-tip' | translate }}</md-tooltip>
215 </md-button> 218 </md-button>
216 -  
217 <md-button class="md-primary md-raised" 219 <md-button class="md-primary md-raised"
218 ng-click="vm.saveAttributeConfig()" 220 ng-click="vm.saveAttributeConfig()"
219 ng-if="vm.configurations.remoteConfiguration" 221 ng-if="vm.configurations.remoteConfiguration"
220 ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty" 222 ng-disabled="gatewayConfiguration.$invalid || !gatewayConfiguration.$dirty"
221 aria-label="{{ 'gateway.save-tip' | translate }}"> 223 aria-label="{{ 'gateway.save-tip' | translate }}">
222 {{'action.save' | translate }} 224 {{'action.save' | translate }}
223 - <md-tooltip ng-if="vm.configurations.remoteConfiguration">{{'gateway.save-tip' | translate }}</md-tooltip> 225 + <md-tooltip ng-if="vm.configurations.remoteConfiguration">{{'gateway.save-tip' | translate }}
  226 + </md-tooltip>
224 </md-button> 227 </md-button>
225 </section> 228 </section>
226 </form> 229 </form>
@@ -1201,7 +1201,12 @@ @@ -1201,7 +1201,12 @@
1201 "tls-path-private-key": "Path to private key on gateway", 1201 "tls-path-private-key": "Path to private key on gateway",
1202 "toggle-fullscreen": "Toggle fullscreen", 1202 "toggle-fullscreen": "Toggle fullscreen",
1203 "transformer-json-config": "Configuration JSON*", 1203 "transformer-json-config": "Configuration JSON*",
1204 - "update-config": "Add/update configuration JSON" 1204 + "update-config": "Add/update configuration JSON",
  1205 + "state-title": "Gateway state",
  1206 + "show-config-tip": "Show gateway configuration",
  1207 + "title-show-config": "Show gateway configuration",
  1208 + "read-only": "Read only",
  1209 + "read-write": ""
1205 }, 1210 },
1206 "grid": { 1211 "grid": {
1207 "delete-item-title": "Are you sure you want to delete this item?", 1212 "delete-item-title": "Are you sure you want to delete this item?",