thingsboard-aplcache

Details

diff --git a/application/src/main/data/json/system/widget_bundles/gateway_widgets.json b/application/src/main/data/json/system/widget_bundles/gateway_widgets.json
new file mode 100644
index 0000000..c963835
--- /dev/null
+++ b/application/src/main/data/json/system/widget_bundles/gateway_widgets.json
@@ -0,0 +1,25 @@
+{
+  "widgetsBundle": {
+    "alias": "gateway_widgets",
+    "title": "Gateway widgets",
+    "image": null
+  },
+  "widgetTypes": [
+    {
+      "alias": "extension_configuration_widget",
+      "name": "Extensions table",
+      "descriptor": {
+        "type": "latest",
+        "sizeX": 9,
+        "sizeY": 6.5,
+        "resources": [],
+        "templateHtml": "<tb-extensions-table-widget \n    ctx=\"ctx\">\n</tb-extensions-table-widget>",
+        "templateCss": "#container {\n    overflow: auto;\n}",
+        "controllerScript": "self.onInit = function() {\n    var scope = self.ctx.$scope;\n    scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n}\n\nself.onResize = function() {\n}\n\nself.typeParameters = function() {\n    return {\n        maxDatasources: 1\n    };\n}\n\nself.onDestroy = function() {\n}\n",
+        "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"ExtensionTableSettings\",\n        \"properties\": {\n            \"extensionsTitle\": {\n                \"title\": \"Extension table title\",\n                \"type\": \"string\",\n                \"default\": \"\"\n            }\n        },\n        \"required\": []\n    },\n    \"form\": [\n        \"extensionsTitle\"\n    ]\n}",
+        "dataKeySettingsSchema": "{}\n",
+        "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\":\"4px\",\"settings\":{},\"title\":\"Extensions table\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"18px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ui/src/app/extension/extensions-forms/extension-form.scss b/ui/src/app/extension/extensions-forms/extension-form.scss
index cc3e052..97ac717 100644
--- a/ui/src/app/extension/extensions-forms/extension-form.scss
+++ b/ui/src/app/extension/extensions-forms/extension-form.scss
@@ -33,6 +33,9 @@
   .dropdown-section {
     margin-bottom: 30px;
   }
+  v-pane.inner-invalid > v-pane-header {
+    border-bottom: 2px solid rgb(221,44,0);
+  }
 }
 
 .extension-form.extension-mqtt {
diff --git a/ui/src/app/extension/extensions-forms/extension-form-http.directive.js b/ui/src/app/extension/extensions-forms/extension-form-http.directive.js
index 9484ab4..37a9444 100644
--- a/ui/src/app/extension/extensions-forms/extension-form-http.directive.js
+++ b/ui/src/app/extension/extensions-forms/extension-form-http.directive.js
@@ -120,6 +120,18 @@ export default function ExtensionFormHttpDirective($compile, $templateCache, $tr
                 }
             }
         };
+
+        scope.collapseValidation = function(index, id) {
+            var invalidState = angular.element('#'+id+':has(.ng-invalid)');
+            if(invalidState.length) {
+                invalidState.addClass('inner-invalid');
+            }
+        };
+
+        scope.expandValidation = function (index, id) {
+            var invalidState = angular.element('#'+id);
+            invalidState.removeClass('inner-invalid');
+        };
         
         $compile(element.contents())(scope);
     };
diff --git a/ui/src/app/extension/extensions-forms/extension-form-http.tpl.html b/ui/src/app/extension/extensions-forms/extension-form-http.tpl.html
index 8202d29..b39794a 100644
--- a/ui/src/app/extension/extensions-forms/extension-form-http.tpl.html
+++ b/ui/src/app/extension/extensions-forms/extension-form-http.tpl.html
@@ -22,7 +22,7 @@
         </md-card-title-text>
     </md-card-title>
     <md-card-content>
-        <v-accordion id="http-converter-configs-accordion" class="vAccordion--default">
+        <v-accordion id="http-converter-configs-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
             <v-pane id="http-converters-pane" expanded="true">
                 <v-pane-header>
                     {{ 'extension.converter-configurations' | translate }}
@@ -55,8 +55,8 @@
                                             <label translate>extension.token</label>
                                             <input name="httpToken" ng-model="config.token" parse-to-null>
                                         </md-input-container>
-                                        <v-accordion id="http-converters-accordion" class="vAccordion--default">
-                                            <v-pane id="http-converters-pane" expanded="true">
+                                        <v-accordion id="http-converters-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="http-converters-pane_{{configIndex}}" expanded="true">
                                                 <v-pane-header>
                                                     {{ 'extension.converters' | translate }}
                                                 </v-pane-header>
@@ -93,8 +93,8 @@
                                                                             </div>
                                                                         </md-input-container>
 
-                                                                        <v-accordion id="http-attributes-accordion" class="vAccordion--default">
-                                                                            <v-pane id="http-attributes-pane">
+                                                                        <v-accordion id="http-attributes-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                                                            <v-pane id="http-attributes-pane_{{configIndex}}{{converterIndex}}">
                                                                                 <v-pane-header>
                                                                                     {{ 'extension.attributes' | translate }}
                                                                                 </v-pane-header>
@@ -185,8 +185,8 @@
                                                                         </v-accordion>
 
 
-                                                                        <v-accordion id="http-timeseries-accordion" class="vAccordion--default">
-                                                                            <v-pane id="http-timeseries-pane">
+                                                                        <v-accordion id="http-timeseries-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                                                            <v-pane id="http-timeseries-pane_{{configIndex}}{{converterIndex}}">
                                                                                 <v-pane-header>
                                                                                     {{ 'extension.timeseries' | translate }}
                                                                                 </v-pane-header>
diff --git a/ui/src/app/extension/extensions-forms/extension-form-mqtt.directive.js b/ui/src/app/extension/extensions-forms/extension-form-mqtt.directive.js
index 41e9aad..39a1eb8 100644
--- a/ui/src/app/extension/extensions-forms/extension-form-mqtt.directive.js
+++ b/ui/src/app/extension/extensions-forms/extension-form-mqtt.directive.js
@@ -321,6 +321,18 @@ export default function ExtensionFormHttpDirective($compile, $templateCache, $tr
             }
         };
 
+        scope.collapseValidation = function(index, id) {
+            var invalidState = angular.element('#'+id+':has(.ng-invalid)');
+            if(invalidState.length) {
+                invalidState.addClass('inner-invalid');
+            }
+        };
+
+        scope.expandValidation = function (index, id) {
+            var invalidState = angular.element('#'+id);
+            invalidState.removeClass('inner-invalid');
+        };
+
         $compile(element.contents())(scope);
     };
 
diff --git a/ui/src/app/extension/extensions-forms/extension-form-mqtt.tpl.html b/ui/src/app/extension/extensions-forms/extension-form-mqtt.tpl.html
index 7950c75..f665fb0 100644
--- a/ui/src/app/extension/extensions-forms/extension-form-mqtt.tpl.html
+++ b/ui/src/app/extension/extensions-forms/extension-form-mqtt.tpl.html
@@ -22,7 +22,7 @@
         </md-card-title-text>
     </md-card-title>
     <md-card-content>
-        <v-accordion id="mqtt-brokers-accordion" class="vAccordion--default">
+        <v-accordion id="mqtt-brokers-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
             <v-pane id="mqtt-brokers-pane" expanded="true">
                 <v-pane-header>
                     {{ 'extension.brokers' | translate }}
@@ -161,8 +161,8 @@
                                             </div>
                                         </section>
 
-                                        <v-accordion id="mqtt-mapping-accordion" class="vAccordion--default">
-                                            <v-pane id="mqtt-mapping-pane">
+                                        <v-accordion id="mqtt-mapping-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="mqtt-mapping-pane_{{brokerIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.mapping' | translate }}
                                                 </v-pane-header>
@@ -286,8 +286,8 @@
                                                                             </div>
                                                                         </div>
 
-                                                                        <v-accordion ng-if='map.converterType =="json"' id="mqtt-attributes-accordion" class="vAccordion--default">
-                                                                            <v-pane id="mqtt-attributes-pane">
+                                                                        <v-accordion ng-if='map.converterType =="json"' id="mqtt-attributes-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                                                            <v-pane id="mqtt-attributes-pane_{{brokerIndex}}{{mapIndex}}">
                                                                                 <v-pane-header>
                                                                                     {{ 'extension.attributes' | translate }}
                                                                                 </v-pane-header>
@@ -346,8 +346,8 @@
                                                                             </v-pane>
                                                                         </v-accordion>
 
-                                                                        <v-accordion ng-if='map.converterType =="json"' id="mqtt-timeseries-accordion" class="vAccordion--default">
-                                                                            <v-pane id="mqtt-timeseries-pane">
+                                                                        <v-accordion ng-if='map.converterType =="json"' id="mqtt-timeseries-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                                                            <v-pane id="mqtt-timeseries-pane_{{brokerIndex}}{{mapIndex}}">
                                                                                 <v-pane-header>
                                                                                     {{ 'extension.timeseries' | translate }}
                                                                                 </v-pane-header>
@@ -422,8 +422,8 @@
                                             </v-pane>
                                         </v-accordion>
 
-                                        <v-accordion id="mqtt-connect-requests-accordion" class="vAccordion--default">
-                                            <v-pane id="mqtt-connect-requests-pane">
+                                        <v-accordion id="mqtt-connect-requests-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="mqtt-connect-requests-pane_{{brokerIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.connect-requests' | translate }}
                                                 </v-pane-header>
@@ -489,8 +489,8 @@
                                             </v-pane>
                                         </v-accordion>
 
-                                        <v-accordion id="mqtt-disconnect-requests-accordion" class="vAccordion--default">
-                                            <v-pane id="mqtt-disconnect-requests-pane">
+                                        <v-accordion id="mqtt-disconnect-requests-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="mqtt-disconnect-requests-pane_{{brokerIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.disconnect-requests' | translate }}
                                                 </v-pane-header>
@@ -556,8 +556,8 @@
                                             </v-pane>
                                         </v-accordion>
 
-                                        <v-accordion id="mqtt-attribute-requests-accordion" class="vAccordion--default">
-                                            <v-pane id="mqtt-attribute-requests-pane">
+                                        <v-accordion id="mqtt-attribute-requests-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="mqtt-attribute-requests-pane_{{brokerIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.attribute-requests' | translate }}
                                                 </v-pane-header>
@@ -701,8 +701,8 @@
                                             </v-pane>
                                         </v-accordion>
 
-                                        <v-accordion id="mqtt-attribute-updates-accordion" class="vAccordion--default">
-                                            <v-pane id="mqtt-attribute-updates-pane">
+                                        <v-accordion id="mqtt-attribute-updates-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="mqtt-attribute-updates-pane_{{brokerIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.attribute-updates' | translate }}
                                                 </v-pane-header>
@@ -764,8 +764,8 @@
                                             </v-pane>
                                         </v-accordion>
 
-                                        <v-accordion id="mqtt-server-side-rpc-accordion" class="vAccordion--default">
-                                            <v-pane id="mqtt-server-side-rpc-pane">
+                                        <v-accordion id="mqtt-server-side-rpc-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="mqtt-server-side-rpc-pane_{{brokerIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.server-side-rpc' | translate }}
                                                 </v-pane-header>
diff --git a/ui/src/app/extension/extensions-forms/extension-form-opc.directive.js b/ui/src/app/extension/extensions-forms/extension-form-opc.directive.js
index 7eeeb29..fc69b68 100644
--- a/ui/src/app/extension/extensions-forms/extension-form-opc.directive.js
+++ b/ui/src/app/extension/extensions-forms/extension-form-opc.directive.js
@@ -148,6 +148,18 @@ export default function ExtensionFormOpcDirective($compile, $templateCache, $tra
 
         };
 
+        scope.collapseValidation = function(index, id) {
+            var invalidState = angular.element('#'+id+':has(.ng-invalid)');
+            if(invalidState.length) {
+                invalidState.addClass('inner-invalid');
+            }
+        };
+
+        scope.expandValidation = function (index, id) {
+            var invalidState = angular.element('#'+id);
+            invalidState.removeClass('inner-invalid');
+        };
+
     };
 
     return {
diff --git a/ui/src/app/extension/extensions-forms/extension-form-opc.tpl.html b/ui/src/app/extension/extensions-forms/extension-form-opc.tpl.html
index 3cc1e1b..01b4f86 100644
--- a/ui/src/app/extension/extensions-forms/extension-form-opc.tpl.html
+++ b/ui/src/app/extension/extensions-forms/extension-form-opc.tpl.html
@@ -23,8 +23,8 @@
     </md-card-title>
 
     <md-card-content>
-        <v-accordion id="http-server-configs-accordion" class="vAccordion--default">
-            <v-pane id="http-servers-pane" expanded="true">
+        <v-accordion id="opc-server-configs-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+            <v-pane id="opc-servers-pane" expanded="true">
                 <v-pane-header>
                     {{ 'extension.opc-server' | translate }}
                 </v-pane-header>
@@ -197,8 +197,8 @@
                                             </md-input-container>
                                         </div>
 
-                                        <v-accordion id="opc-attributes-accordion" class="vAccordion--default">
-                                            <v-pane id="opc-attributes-pane" expanded="true">
+                                        <v-accordion id="opc-keystore-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="opc-keystore-pane__{{serverIndex}}" expanded="true">
                                                 <v-pane-header>
                                                     {{ 'extension.opc-keystore' | translate }}
                                                 </v-pane-header>
@@ -277,10 +277,10 @@
                                         </v-accordion>
 
 
-                                        <v-accordion id="opc-attributes-accordion"
+                                        <v-accordion id="opc-mapping-accordion"
                                                      class="vAccordion--default"
-                                        >
-                                            <v-pane id="opc-attributes-pane">
+                                                     onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                            <v-pane id="opc-mapping-pane_{{serverIndex}}">
                                                 <v-pane-header>
                                                     {{ 'extension.mapping' | translate }}
                                                 </v-pane-header>
@@ -333,8 +333,8 @@
 
                                                                         <v-accordion id="opc-attributes-accordion"
                                                                                      class="vAccordion--default"
-                                                                        >
-                                                                            <v-pane id="opc-attributes-pane">
+                                                                                     onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                                                            <v-pane id="opc-attributes-pane_{{serverIndex}}{{mapIndex}}">
                                                                                 <v-pane-header>
                                                                                     {{ 'extension.attributes' | translate }}
                                                                                 </v-pane-header>
@@ -425,8 +425,8 @@
                                                                             </v-pane>
                                                                         </v-accordion>
 
-                                                                        <v-accordion id="opc-timeseries-accordion" class="vAccordion--default">
-                                                                            <v-pane id="opc-timeseries-pane">
+                                                                        <v-accordion id="opc-timeseries-accordion" class="vAccordion--default" onexpand="expandValidation(index, id)" oncollapse="collapseValidation(index, id)">
+                                                                            <v-pane id="opc-timeseries-pane_{{serverIndex}}{{mapIndex}}">
                                                                                 <v-pane-header>
                                                                                     {{ 'extension.timeseries' | translate }}
                                                                                 </v-pane-header>