thingsboard-aplcache
Changes
ui/src/app/api/widget.service.js 1(+1 -0)
ui/src/app/common/types.constant.js 8(+8 -0)
ui/src/app/dashboard/dashboard.tpl.html 14(+12 -2)
ui/src/locale/en_US.json 2(+2 -0)
Details
diff --git a/dao/src/main/resources/system-data.cql b/dao/src/main/resources/system-data.cql
index 3b8e320..76ffd24 100644
--- a/dao/src/main/resources/system-data.cql
+++ b/dao/src/main/resources/system-data.cql
@@ -83,6 +83,11 @@ VALUES ( now ( ), minTimeuuid ( 0 ), 'cards', 'timeseries_table',
'Timeseries table' );
INSERT INTO "thingsboard"."widget_type" ( "id", "tenant_id", "bundle_alias", "alias", "descriptor", "name" )
+VALUES ( now ( ), minTimeuuid ( 0 ), 'cards', 'html_card',
+'{"type":"static","sizeX":7.5,"sizeY":3,"resources":[],"templateHtml":"","templateCss":"","controllerScript":"fns.init = function(containerElement, settings, datasources,\n data) {\n\n var container = $(containerElement);\n \n var cssParser = new cssjs();\n cssParser.testMode = false;\n var namespace = ''html-card-'' + hashCode(settings.cardCss);\n cssParser.cssPreviewNamespace = namespace;\n cssParser.createStyleElement(namespace, settings.cardCss);\n container.addClass(namespace);\n container.html(settings.cardHtml);\n \n function hashCode(str) {\n var hash = 0;\n var i, char;\n if (str.length === 0) return hash;\n for (i = 0; i < str.length; i++) {\n char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return hash;\n }\n\n}\n\n\nfns.redraw = function(containerElement, width, height, data, timeWindow, sizeChanged) {\n\n};","settingsSchema":"{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"required\": [\"cardHtml\"],\n \"properties\": {\n \"cardCss\": {\n \"title\": \"CSS\",\n \"type\": \"string\",\n \"default\": \".card {\\n font-weight: bold; \\n}\"\n },\n \"cardHtml\": {\n \"title\": \"HTML\",\n \"type\": \"string\",\n \"default\": \"<div class=''card''>HTML code here</div>\"\n }\n }\n },\n \"form\": [\n {\n \"key\": \"cardCss\",\n \"type\": \"css\"\n }, \n {\n \"key\": \"cardHtml\",\n \"type\": \"html\"\n } \n ]\n}","dataKeySettingsSchema":"{}\n","defaultConfig":"{\"datasources\":[{\"type\":\"static\",\"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\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"cardHtml\":\"<div class=''card''>HTML code here</div>\",\"cardCss\":\".card {\\n font-weight: bold;\\n font-size: 32px;\\n color: #999;\\n width: 100%;\\n height: 100%;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\"},\"title\":\"HTML Card\",\"dropShadow\":true}"}',
+'HTML Card' );
+
+INSERT INTO "thingsboard"."widget_type" ( "id", "tenant_id", "bundle_alias", "alias", "descriptor", "name" )
VALUES ( now ( ), minTimeuuid ( 0 ), 'analogue_gauges', 'speed_gauge_canvas_gauges',
'{"type":"latest","sizeX":7,"sizeY":5,"resources":[],"templateHtml":"<canvas id=\"radialGauge\"></canvas>\n","templateCss":"","controllerScript":"var gauge;\n\nfns.init = function(containerElement, settings, datasources,\n data) {\n gauge = new TbAnalogueRadialGauge(containerElement, settings, data, ''radialGauge''); \n\n}\n\n\nfns.redraw = function(containerElement, width, height, data, timeWindow, sizeChanged) {\n gauge.redraw(width, height, data, sizeChanged);\n};\n\nfns.destroy = function() {\n}\n","settingsSchema":"{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\",\n \"default\": 0\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\",\n \"default\": 100\n },\n \"unitTitle\": {\n \"title\": \"Unit title\",\n \"type\": \"string\",\n \"default\": null\n },\n \"showUnitTitle\": {\n \"title\": \"Show unit title\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"units\": {\n \"title\": \"Units\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"majorTicksCount\": {\n \"title\": \"Major ticks count\",\n \"type\": \"number\",\n \"default\": null\n },\n \"minorTicks\": {\n \"title\": \"Minor ticks count\",\n \"type\": \"number\",\n \"default\": 2\n },\n \"valueBox\": {\n \"title\": \"Show value box\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"valueInt\": {\n \"title\": \"Digits count for integer part of value\",\n \"type\": \"number\",\n \"default\": 3\n },\n \"valueDec\": {\n \"title\": \"Digits count for decimal part of value\",\n \"type\": \"number\",\n \"default\": 2\n },\n \"defaultColor\": {\n \"title\": \"Default color\",\n \"type\": \"string\",\n \"default\": null\n },\n \"colorPlate\": {\n \"title\": \"Plate color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"colorMajorTicks\": {\n \"title\": \"Major ticks color\",\n \"type\": \"string\",\n \"default\": \"#444\"\n },\n \"colorMinorTicks\": {\n \"title\": \"Minor ticks color\",\n \"type\": \"string\",\n \"default\": \"#666\"\n },\n \"colorNeedle\": {\n \"title\": \"Needle color\",\n \"type\": \"string\",\n \"default\": null\n },\n \"colorNeedleEnd\": {\n \"title\": \"Needle color - end gradient\",\n \"type\": \"string\",\n \"default\": null\n },\n \"colorNeedleShadowUp\": {\n \"title\": \"Upper half of the needle shadow color\",\n \"type\": \"string\",\n \"default\": \"rgba(2,255,255,0.2)\"\n },\n \"colorNeedleShadowDown\": {\n \"title\": \"Drop shadow needle color.\",\n \"type\": \"string\",\n \"default\": \"rgba(188,143,143,0.45)\"\n },\n \"colorValueBoxRect\": {\n \"title\": \"Value box rectangle stroke color\",\n \"type\": \"string\",\n \"default\": \"#888\"\n },\n \"colorValueBoxRectEnd\": {\n \"title\": \"Value box rectangle stroke color - end gradient\",\n \"type\": \"string\",\n \"default\": \"#666\"\n },\n \"colorValueBoxBackground\": {\n \"title\": \"Value box background color\",\n \"type\": \"string\",\n \"default\": \"#babab2\"\n },\n \"colorValueBoxShadow\": {\n \"title\": \"Value box shadow color\",\n \"type\": \"string\",\n \"default\": \"rgba(0,0,0,1)\"\n },\n \"highlights\": {\n \"title\": \"Highlights\",\n \"type\": \"array\",\n \"items\": {\n \"title\": \"Highlight\",\n \"type\": \"object\",\n \"properties\": {\n \"from\": {\n \"title\": \"From\",\n \"type\": \"number\"\n },\n \"to\": {\n \"title\": \"To\",\n \"type\": \"number\"\n },\n \"color\": {\n \"title\": \"Color\",\n \"type\": \"string\"\n }\n }\n }\n },\n \"highlightsWidth\": {\n \"title\": \"Highlights width\",\n \"type\": \"number\",\n \"default\": 15\n },\n \"showBorder\": {\n \"title\": \"Show border\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"numbersFont\": {\n \"title\": \"Tick numbers font\",\n \"type\": \"object\",\n \"properties\": {\n \"family\": {\n \"title\": \"Font family\",\n \"type\": \"string\",\n \"default\": \"RobotoDraft\"\n },\n \"size\": {\n \"title\": \"Size\",\n \"type\": \"number\",\n \"default\": 18\n },\n \"style\": {\n \"title\": \"Style\",\n \"type\": \"string\",\n \"default\": \"normal\"\n },\n \"weight\": {\n \"title\": \"Weight\",\n \"type\": \"string\",\n \"default\": \"500\"\n },\n \"color\": {\n \"title\": \"color\",\n \"type\": \"string\",\n \"default\": null\n }\n }\n },\n \"titleFont\": {\n \"title\": \"Title text font\",\n \"type\": \"object\",\n \"properties\": {\n \"family\": {\n \"title\": \"Font family\",\n \"type\": \"string\",\n \"default\": \"RobotoDraft\"\n },\n \"size\": {\n \"title\": \"Size\",\n \"type\": \"number\",\n \"default\": 24\n },\n \"style\": {\n \"title\": \"Style\",\n \"type\": \"string\",\n \"default\": \"normal\"\n },\n \"weight\": {\n \"title\": \"Weight\",\n \"type\": \"string\",\n \"default\": \"500\"\n },\n \"color\": {\n \"title\": \"color\",\n \"type\": \"string\",\n \"default\": \"#888\"\n }\n }\n },\n \"unitsFont\": {\n \"title\": \"Units text font\",\n \"type\": \"object\",\n \"properties\": {\n \"family\": {\n \"title\": \"Font family\",\n \"type\": \"string\",\n \"default\": \"RobotoDraft\"\n },\n \"size\": {\n \"title\": \"Size\",\n \"type\": \"number\",\n \"default\": 22\n },\n \"style\": {\n \"title\": \"Style\",\n \"type\": \"string\",\n \"default\": \"normal\"\n },\n \"weight\": {\n \"title\": \"Weight\",\n \"type\": \"string\",\n \"default\": \"500\"\n },\n \"color\": {\n \"title\": \"color\",\n \"type\": \"string\",\n \"default\": \"#888\"\n }\n }\n },\n \"valueFont\": {\n \"title\": \"Value text font\",\n \"type\": \"object\",\n \"properties\": {\n \"family\": {\n \"title\": \"Font family\",\n \"type\": \"string\",\n \"default\": \"RobotoDraft\"\n },\n \"size\": {\n \"title\": \"Size\",\n \"type\": \"number\",\n \"default\": 40\n },\n \"style\": {\n \"title\": \"Style\",\n \"type\": \"string\",\n \"default\": \"normal\"\n },\n \"weight\": {\n \"title\": \"Weight\",\n \"type\": \"string\",\n \"default\": \"500\"\n },\n \"color\": {\n \"title\": \"color\",\n \"type\": \"string\",\n \"default\": \"#444\"\n },\n \"shadowColor\": {\n \"title\": \"Shadow color\",\n \"type\": \"string\",\n \"default\": \"rgba(0,0,0,0.3)\"\n }\n }\n },\n \"animation\": {\n \"title\": \"Enable animation\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"animationDuration\": {\n \"title\": \"Animation duration\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"animationRule\": {\n \"title\": \"Animation rule\",\n \"type\": \"string\",\n \"default\": \"cycle\"\n },\n \"startAngle\": {\n \"title\": \"Start ticks angle\",\n \"type\": \"number\",\n \"default\": 45\n },\n \"ticksAngle\": {\n \"title\": \"Ticks angle\",\n \"type\": \"number\",\n \"default\": 270\n },\n \"needleCircleSize\": {\n \"title\": \"Needle circle size\",\n \"type\": \"number\",\n \"default\": 10\n }\n },\n \"required\": []\n },\n \"form\": [\n \"startAngle\",\n \"ticksAngle\",\n \"needleCircleSize\",\n \"minValue\",\n \"maxValue\",\n \"unitTitle\",\n \"showUnitTitle\",\n \"units\",\n \"majorTicksCount\",\n \"minorTicks\",\n \"valueBox\",\n \"valueInt\",\n \"valueDec\",\n {\n \"key\": \"defaultColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorPlate\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorMajorTicks\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorMinorTicks\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorNeedle\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorNeedleEnd\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorNeedleShadowUp\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorNeedleShadowDown\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorValueBoxRect\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorValueBoxRectEnd\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorValueBoxBackground\",\n \"type\": \"color\"\n },\n {\n \"key\": \"colorValueBoxShadow\",\n \"type\": \"color\"\n },\n {\n \"key\": \"highlights\",\n \"items\": [\n \"highlights[].from\",\n \"highlights[].to\",\n {\n \"key\": \"highlights[].color\",\n \"type\": \"color\"\n }\n ]\n },\n \"highlightsWidth\",\n \"showBorder\",\n {\n \"key\": \"numbersFont\",\n \"items\": [\n \"numbersFont.family\",\n \"numbersFont.size\",\n {\n \"key\": \"numbersFont.style\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"italic\",\n \"label\": \"Italic\"\n },\n {\n \"value\": \"oblique\",\n \"label\": \"Oblique\"\n }\n ]\n },\n {\n \"key\": \"numbersFont.weight\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"bold\",\n \"label\": \"Bold\"\n },\n {\n \"value\": \"bolder\",\n \"label\": \"Bolder\"\n },\n {\n \"value\": \"lighter\",\n \"label\": \"Lighter\"\n },\n {\n \"value\": \"100\",\n \"label\": \"100\"\n },\n {\n \"value\": \"200\",\n \"label\": \"200\"\n },\n {\n \"value\": \"300\",\n \"label\": \"300\"\n },\n {\n \"value\": \"400\",\n \"label\": \"400\"\n },\n {\n \"value\": \"500\",\n \"label\": \"500\"\n },\n {\n \"value\": \"600\",\n \"label\": \"600\"\n },\n {\n \"value\": \"700\",\n \"label\": \"800\"\n },\n {\n \"value\": \"800\",\n \"label\": \"800\"\n },\n {\n \"value\": \"900\",\n \"label\": \"900\"\n }\n ]\n },\n {\n \"key\": \"numbersFont.color\",\n \"type\": \"color\"\n }\n ]\n },\n {\n \"key\": \"titleFont\",\n \"items\": [\n \"titleFont.family\",\n \"titleFont.size\",\n {\n \"key\": \"titleFont.style\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"italic\",\n \"label\": \"Italic\"\n },\n {\n \"value\": \"oblique\",\n \"label\": \"Oblique\"\n }\n ]\n },\n {\n \"key\": \"titleFont.weight\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"bold\",\n \"label\": \"Bold\"\n },\n {\n \"value\": \"bolder\",\n \"label\": \"Bolder\"\n },\n {\n \"value\": \"lighter\",\n \"label\": \"Lighter\"\n },\n {\n \"value\": \"100\",\n \"label\": \"100\"\n },\n {\n \"value\": \"200\",\n \"label\": \"200\"\n },\n {\n \"value\": \"300\",\n \"label\": \"300\"\n },\n {\n \"value\": \"400\",\n \"label\": \"400\"\n },\n {\n \"value\": \"500\",\n \"label\": \"500\"\n },\n {\n \"value\": \"600\",\n \"label\": \"600\"\n },\n {\n \"value\": \"700\",\n \"label\": \"800\"\n },\n {\n \"value\": \"800\",\n \"label\": \"800\"\n },\n {\n \"value\": \"900\",\n \"label\": \"900\"\n }\n ]\n },\n {\n \"key\": \"titleFont.color\",\n \"type\": \"color\"\n }\n ]\n },\n {\n \"key\": \"unitsFont\",\n \"items\": [\n \"unitsFont.family\",\n \"unitsFont.size\",\n {\n \"key\": \"unitsFont.style\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"italic\",\n \"label\": \"Italic\"\n },\n {\n \"value\": \"oblique\",\n \"label\": \"Oblique\"\n }\n ]\n },\n {\n \"key\": \"unitsFont.weight\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"bold\",\n \"label\": \"Bold\"\n },\n {\n \"value\": \"bolder\",\n \"label\": \"Bolder\"\n },\n {\n \"value\": \"lighter\",\n \"label\": \"Lighter\"\n },\n {\n \"value\": \"100\",\n \"label\": \"100\"\n },\n {\n \"value\": \"200\",\n \"label\": \"200\"\n },\n {\n \"value\": \"300\",\n \"label\": \"300\"\n },\n {\n \"value\": \"400\",\n \"label\": \"400\"\n },\n {\n \"value\": \"500\",\n \"label\": \"500\"\n },\n {\n \"value\": \"600\",\n \"label\": \"600\"\n },\n {\n \"value\": \"700\",\n \"label\": \"800\"\n },\n {\n \"value\": \"800\",\n \"label\": \"800\"\n },\n {\n \"value\": \"900\",\n \"label\": \"900\"\n }\n ]\n },\n {\n \"key\": \"unitsFont.color\",\n \"type\": \"color\"\n }\n ]\n },\n {\n \"key\": \"valueFont\",\n \"items\": [\n \"valueFont.family\",\n \"valueFont.size\",\n {\n \"key\": \"valueFont.style\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"italic\",\n \"label\": \"Italic\"\n },\n {\n \"value\": \"oblique\",\n \"label\": \"Oblique\"\n }\n ]\n },\n {\n \"key\": \"valueFont.weight\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"normal\",\n \"label\": \"Normal\"\n },\n {\n \"value\": \"bold\",\n \"label\": \"Bold\"\n },\n {\n \"value\": \"bolder\",\n \"label\": \"Bolder\"\n },\n {\n \"value\": \"lighter\",\n \"label\": \"Lighter\"\n },\n {\n \"value\": \"100\",\n \"label\": \"100\"\n },\n {\n \"value\": \"200\",\n \"label\": \"200\"\n },\n {\n \"value\": \"300\",\n \"label\": \"300\"\n },\n {\n \"value\": \"400\",\n \"label\": \"400\"\n },\n {\n \"value\": \"500\",\n \"label\": \"500\"\n },\n {\n \"value\": \"600\",\n \"label\": \"600\"\n },\n {\n \"value\": \"700\",\n \"label\": \"800\"\n },\n {\n \"value\": \"800\",\n \"label\": \"800\"\n },\n {\n \"value\": \"900\",\n \"label\": \"900\"\n }\n ]\n },\n {\n \"key\": \"valueFont.color\",\n \"type\": \"color\"\n },\n {\n \"key\": \"valueFont.shadowColor\",\n \"type\": \"color\"\n }\n ]\n }, \n \"animation\",\n \"animationDuration\",\n {\n \"key\": \"animationRule\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"linear\",\n \"label\": \"Linear\"\n },\n {\n \"value\": \"quad\",\n \"label\": \"Quad\"\n },\n {\n \"value\": \"quint\",\n \"label\": \"Quint\"\n },\n {\n \"value\": \"cycle\",\n \"label\": \"Cycle\"\n },\n {\n \"value\": \"bounce\",\n \"label\": \"Bounce\"\n },\n {\n \"value\": \"elastic\",\n \"label\": \"Elastic\"\n },\n {\n \"value\": \"dequad\",\n \"label\": \"Dequad\"\n },\n {\n \"value\": \"dequint\",\n \"label\": \"Dequint\"\n },\n {\n \"value\": \"decycle\",\n \"label\": \"Decycle\"\n },\n {\n \"value\": \"debounce\",\n \"label\": \"Debounce\"\n },\n {\n \"value\": \"delastic\",\n \"label\": \"Delastic\"\n }\n ]\n }\n ]\n}","dataKeySettingsSchema":"{}\n","defaultConfig":"{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.7282710489093589,\"funcBody\":\"var value = prevValue + Math.random() * 50 - 25;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 220) {\\n\\tvalue = 220;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"maxValue\":180,\"startAngle\":45,\"ticksAngle\":270,\"showBorder\":false,\"defaultColor\":\"#e65100\",\"needleCircleSize\":7,\"highlights\":[{\"from\":80,\"to\":120,\"color\":\"#fdd835\"},{\"color\":\"#e57373\",\"from\":120,\"to\":180}],\"showUnitTitle\":false,\"colorPlate\":\"#fff\",\"colorMajorTicks\":\"#444\",\"colorMinorTicks\":\"#666\",\"minorTicks\":2,\"valueInt\":3,\"minValue\":0,\"valueDec\":0,\"highlightsWidth\":15,\"valueBox\":true,\"animation\":true,\"animationDuration\":1500,\"animationRule\":\"linear\",\"colorNeedleShadowUp\":\"rgba(2, 255, 255, 0)\",\"colorNeedleShadowDown\":\"rgba(188, 143, 143, 0.78)\",\"units\":\"MPH\",\"majorTicksCount\":9,\"numbersFont\":{\"family\":\"RobotoDraft\",\"size\":22,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"titleFont\":{\"family\":\"RobotoDraft\",\"size\":24,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#888\"},\"unitsFont\":{\"family\":\"RobotoDraft\",\"size\":28,\"style\":\"normal\",\"weight\":\"500\",\"color\":\"#616161\"},\"valueFont\":{\"size\":32,\"style\":\"normal\",\"weight\":\"normal\",\"shadowColor\":\"rgba(0, 0, 0, 0.49)\",\"color\":\"#444\",\"family\":\"Segment7Standard\"},\"colorValueBoxRect\":\"#888\",\"colorValueBoxRectEnd\":\"#666\",\"colorValueBoxBackground\":\"#babab2\",\"colorValueBoxShadow\":\"rgba(0,0,0,1)\"},\"title\":\"Speed gauge - Canvas Gauges\"}"}',
'Speed gauge - Canvas Gauges' );
ui/src/app/api/widget.service.js 1(+1 -0)
diff --git a/ui/src/app/api/widget.service.js b/ui/src/app/api/widget.service.js
index 23375cb..cde32f0 100644
--- a/ui/src/app/api/widget.service.js
+++ b/ui/src/app/api/widget.service.js
@@ -46,6 +46,7 @@ function WidgetService($rootScope, $http, $q, $filter, $ocLazyLoad, $window, typ
$window.TbAnalogueRadialGauge = TbAnalogueRadialGauge;
$window.TbDigitalGauge = TbDigitalGauge;
$window.TbMapWidget = TbMapWidget;
+ $window.cssjs = cssjs;
var cssParser = new cssjs();
cssParser.testMode = false;
ui/src/app/common/types.constant.js 8(+8 -0)
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index 71bc886..5314038 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -141,6 +141,14 @@ export default angular.module('thingsboard.types', [])
bundleAlias: "gpio_widgets",
alias: "basic_gpio_control"
}
+ },
+ static: {
+ value: "static",
+ name: "widget.static",
+ template: {
+ bundleAlias: "cards",
+ alias: "html_card"
+ }
}
},
systemBundleAlias: {
diff --git a/ui/src/app/components/dashboard.directive.js b/ui/src/app/components/dashboard.directive.js
index 4fc8599..0e89a01 100644
--- a/ui/src/app/components/dashboard.directive.js
+++ b/ui/src/app/components/dashboard.directive.js
@@ -139,6 +139,7 @@ function DashboardController($scope, $rootScope, $element, $timeout, $log, toast
vm.widgetBackgroundColor = widgetBackgroundColor;
vm.widgetPadding = widgetPadding;
vm.showWidgetTitle = showWidgetTitle;
+ vm.dropWidgetShadow = dropWidgetShadow;
vm.hasTimewindow = hasTimewindow;
vm.editWidget = editWidget;
vm.exportWidget = exportWidget;
@@ -521,6 +522,14 @@ function DashboardController($scope, $rootScope, $element, $timeout, $log, toast
}
}
+ function dropWidgetShadow(widget) {
+ if (angular.isDefined(widget.config.dropShadow)) {
+ return widget.config.dropShadow;
+ } else {
+ return true;
+ }
+ }
+
function hasTimewindow(widget) {
return widget.type === types.widgetType.timeseries.value;
}
diff --git a/ui/src/app/components/dashboard.tpl.html b/ui/src/app/components/dashboard.tpl.html
index 111f0d3..cac3d7f 100644
--- a/ui/src/app/components/dashboard.tpl.html
+++ b/ui/src/app/components/dashboard.tpl.html
@@ -28,8 +28,10 @@
<li gridster-item="widget" ng-repeat="widget in vm.widgets">
<md-menu md-position-mode="target target" tb-mousepoint-menu>
<div tb-expand-fullscreen
- expand-button-id="expand-button" on-fullscreen-changed="vm.onWidgetFullscreenChanged(expanded, widget)" layout="column" class="tb-widget md-whiteframe-4dp"
- ng-class="{'tb-highlighted': vm.isHighlighted(widget), 'tb-not-highlighted': vm.isNotHighlighted(widget)}"
+ expand-button-id="expand-button" on-fullscreen-changed="vm.onWidgetFullscreenChanged(expanded, widget)" layout="column" class="tb-widget"
+ ng-class="{'tb-highlighted': vm.isHighlighted(widget),
+ 'tb-not-highlighted': vm.isNotHighlighted(widget),
+ 'md-whiteframe-4dp': vm.dropWidgetShadow(widget)}"
tb-mousedown="vm.widgetMouseDown($event, widget)"
tb-mousemove="vm.widgetMouseMove($event, widget)"
tb-mouseup="vm.widgetMouseUp($event, widget)"
diff --git a/ui/src/app/components/react/json-form-css.jsx b/ui/src/app/components/react/json-form-css.jsx
new file mode 100644
index 0000000..9c5dcc6
--- /dev/null
+++ b/ui/src/app/components/react/json-form-css.jsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import ThingsboardAceEditor from './json-form-ace-editor.jsx';
+import 'brace/mode/css';
+import beautify from 'js-beautify';
+
+const css_beautify = beautify.css;
+
+class ThingsboardCss extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.onTidyCss = this.onTidyCss.bind(this);
+ }
+
+ onTidyCss(css) {
+ return css_beautify(css, {indent_size: 4});
+ }
+
+ render() {
+ return (
+ <ThingsboardAceEditor {...this.props} mode='css' onTidy={this.onTidyCss} {...this.state}></ThingsboardAceEditor>
+ );
+ }
+}
+
+export default ThingsboardCss;
diff --git a/ui/src/app/components/react/json-form-html.jsx b/ui/src/app/components/react/json-form-html.jsx
new file mode 100644
index 0000000..f45952f
--- /dev/null
+++ b/ui/src/app/components/react/json-form-html.jsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2016-2017 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import ThingsboardAceEditor from './json-form-ace-editor.jsx';
+import 'brace/mode/html';
+import beautify from 'js-beautify';
+
+const html_beautify = beautify.html;
+
+class ThingsboardHtml extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.onTidyHtml = this.onTidyHtml.bind(this);
+ }
+
+ onTidyHtml(html) {
+ return html_beautify(html, {indent_size: 4});
+ }
+
+ render() {
+ return (
+ <ThingsboardAceEditor {...this.props} mode='html' onTidy={this.onTidyHtml} {...this.state}></ThingsboardAceEditor>
+ );
+ }
+}
+
+export default ThingsboardHtml;
diff --git a/ui/src/app/components/react/json-form-schema-form.jsx b/ui/src/app/components/react/json-form-schema-form.jsx
index 734ae12..d708d53 100644
--- a/ui/src/app/components/react/json-form-schema-form.jsx
+++ b/ui/src/app/components/react/json-form-schema-form.jsx
@@ -19,6 +19,8 @@ import { utils } from 'react-schema-form';
import ThingsboardArray from './json-form-array.jsx';
import ThingsboardJavaScript from './json-form-javascript.jsx';
import ThingsboardJson from './json-form-json.jsx';
+import ThingsboardHtml from './json-form-html.jsx';
+import ThingsboardCss from './json-form-css.jsx';
import ThingsboardColor from './json-form-color.jsx'
import ThingsboardRcSelect from './json-form-rc-select.jsx';
import ThingsboardNumber from './json-form-number.jsx';
@@ -52,6 +54,8 @@ class ThingsboardSchemaForm extends React.Component {
'array': ThingsboardArray,
'javascript': ThingsboardJavaScript,
'json': ThingsboardJson,
+ 'html': ThingsboardHtml,
+ 'css': ThingsboardCss,
'color': ThingsboardColor,
'rc-select': ThingsboardRcSelect,
'fieldset': ThingsboardFieldSet
diff --git a/ui/src/app/components/widget-config.directive.js b/ui/src/app/components/widget-config.directive.js
index da12a49..775000a 100644
--- a/ui/src/app/components/widget-config.directive.js
+++ b/ui/src/app/components/widget-config.directive.js
@@ -74,11 +74,12 @@ function WidgetConfig($compile, $templateCache, $rootScope, types, utils) {
scope.selectedTab = 0;
scope.title = ngModelCtrl.$viewValue.title;
scope.showTitle = ngModelCtrl.$viewValue.showTitle;
+ scope.dropShadow = angular.isDefined(ngModelCtrl.$viewValue.dropShadow) ? ngModelCtrl.$viewValue.dropShadow : true;
scope.backgroundColor = ngModelCtrl.$viewValue.backgroundColor;
scope.color = ngModelCtrl.$viewValue.color;
scope.padding = ngModelCtrl.$viewValue.padding;
scope.timewindow = ngModelCtrl.$viewValue.timewindow;
- if (scope.widgetType !== types.widgetType.rpc.value) {
+ if (scope.widgetType !== types.widgetType.rpc.value && scope.widgetType !== types.widgetType.static.value) {
if (scope.datasources) {
scope.datasources.splice(0, scope.datasources.length);
} else {
@@ -89,7 +90,7 @@ function WidgetConfig($compile, $templateCache, $rootScope, types, utils) {
scope.datasources.push({value: ngModelCtrl.$viewValue.datasources[i]});
}
}
- } else {
+ } else if (scope.widgetType === types.widgetType.rpc.value) {
if (ngModelCtrl.$viewValue.targetDeviceAliasIds && ngModelCtrl.$viewValue.targetDeviceAliasIds.length > 0) {
var aliasId = ngModelCtrl.$viewValue.targetDeviceAliasIds[0];
if (scope.deviceAliases[aliasId]) {
@@ -140,18 +141,19 @@ function WidgetConfig($compile, $templateCache, $rootScope, types, utils) {
if (scope.widgetType === types.widgetType.rpc.value) {
valid = value && value.targetDeviceAliasIds && value.targetDeviceAliasIds.length > 0;
ngModelCtrl.$setValidity('targetDeviceAliasIds', valid);
- } else {
+ } else if (scope.widgetType !== types.widgetType.static.value) {
valid = value && value.datasources && value.datasources.length > 0;
ngModelCtrl.$setValidity('datasources', valid);
}
}
};
- scope.$watch('title + showTitle + backgroundColor + color + padding + intervalSec', function () {
+ scope.$watch('title + showTitle + dropShadow + backgroundColor + color + padding + intervalSec', function () {
if (ngModelCtrl.$viewValue) {
var value = ngModelCtrl.$viewValue;
value.title = scope.title;
value.showTitle = scope.showTitle;
+ value.dropShadow = scope.dropShadow;
value.backgroundColor = scope.backgroundColor;
value.color = scope.color;
value.padding = scope.padding;
@@ -177,7 +179,8 @@ function WidgetConfig($compile, $templateCache, $rootScope, types, utils) {
}, true);
scope.$watch('datasources', function () {
- if (ngModelCtrl.$viewValue && scope.widgetType !== types.widgetType.rpc.value) {
+ if (ngModelCtrl.$viewValue && scope.widgetType !== types.widgetType.rpc.value
+ && scope.widgetType !== types.widgetType.static.value) {
var value = ngModelCtrl.$viewValue;
if (value.datasources) {
value.datasources.splice(0, value.datasources.length);
@@ -235,7 +238,8 @@ function WidgetConfig($compile, $templateCache, $rootScope, types, utils) {
};
scope.updateDatasourcesAccordionState = function () {
- if (scope.widgetType !== types.widgetType.rpc.value) {
+ if (scope.widgetType !== types.widgetType.rpc.value &&
+ scope.widgetType !== types.widgetType.static.value) {
if (scope.datasourcesAccordion) {
scope.updateDatasourcesAccordionStatePending = false;
var expand = scope.datasources && scope.datasources.length < 4;
diff --git a/ui/src/app/components/widget-config.tpl.html b/ui/src/app/components/widget-config.tpl.html
index d988677..87b3afd 100644
--- a/ui/src/app/components/widget-config.tpl.html
+++ b/ui/src/app/components/widget-config.tpl.html
@@ -31,6 +31,11 @@
ng-model="showTitle">{{ 'widget-config.display-title' | translate }}
</md-checkbox>
</div>
+ <div layout="row" layout-padding>
+ <md-checkbox flex aria-label="{{ 'widget-config.drop-shadow' | translate }}"
+ ng-model="dropShadow">{{ 'widget-config.drop-shadow' | translate }}
+ </md-checkbox>
+ </div>
<div flex
md-color-picker
ng-model="backgroundColor"
@@ -64,7 +69,7 @@
<tb-timewindow as-button="true" flex ng-model="timewindow"></tb-timewindow>
</div>
<v-accordion id="datasources-accordion" control="datasourcesAccordion" class="vAccordion--default"
- ng-show="widgetType !== types.widgetType.rpc.value">
+ ng-show="widgetType !== types.widgetType.rpc.value && widgetType !== types.widgetType.static.value">
<v-pane id="datasources-pane" expanded="forceExpandDatasources">
<v-pane-header>
{{ 'widget-config.datasources' | translate }}
diff --git a/ui/src/app/dashboard/add-widget.controller.js b/ui/src/app/dashboard/add-widget.controller.js
index 02b4e31..2599085 100644
--- a/ui/src/app/dashboard/add-widget.controller.js
+++ b/ui/src/app/dashboard/add-widget.controller.js
@@ -66,6 +66,10 @@ export default function AddWidgetController($scope, widgetService, deviceService
link = 'widgetsConfigRpc';
break;
}
+ case types.widgetType.static.value: {
+ link = 'widgetsConfigStatic';
+ break;
+ }
}
}
return link;
diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js
index 018bda4..3b5d819 100644
--- a/ui/src/app/dashboard/dashboard.controller.js
+++ b/ui/src/app/dashboard/dashboard.controller.js
@@ -41,6 +41,7 @@ export default function DashboardController(types, widgetService, userService,
vm.latestWidgetTypes = [];
vm.timeseriesWidgetTypes = [];
vm.rpcWidgetTypes = [];
+ vm.staticWidgetTypes = [];
vm.widgetEditMode = $state.$current.data.widgetEditMode;
vm.widgets = [];
@@ -82,6 +83,7 @@ export default function DashboardController(types, widgetService, userService,
vm.latestWidgetTypes = [];
vm.timeseriesWidgetTypes = [];
vm.rpcWidgetTypes = [];
+ vm.staticWidgetTypes = [];
if (vm.widgetsBundle) {
var bundleAlias = vm.widgetsBundle.alias;
var isSystem = vm.widgetsBundle.tenantId.id === types.id.nullUid;
@@ -127,6 +129,8 @@ export default function DashboardController(types, widgetService, userService,
vm.latestWidgetTypes.push(widget);
} else if (widgetTypeInfo.type === types.widgetType.rpc.value) {
vm.rpcWidgetTypes.push(widget);
+ } else if (widgetTypeInfo.type === types.widgetType.static.value) {
+ vm.staticWidgetTypes.push(widget);
}
top += sizeY;
loadNextOrComplete(i);
@@ -442,6 +446,10 @@ export default function DashboardController(types, widgetService, userService,
link = 'widgetsConfigRpc';
break;
}
+ case types.widgetType.static.value: {
+ link = 'widgetsConfigStatic';
+ break;
+ }
}
}
return link;
@@ -490,6 +498,7 @@ export default function DashboardController(types, widgetService, userService,
vm.timeseriesWidgetTypes = [];
vm.latestWidgetTypes = [];
vm.rpcWidgetTypes = [];
+ vm.staticWidgetTypes = [];
}
function addWidgetFromType(event, widget) {
ui/src/app/dashboard/dashboard.tpl.html 14(+12 -2)
diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html
index 109c10a..99f9c60 100644
--- a/ui/src/app/dashboard/dashboard.tpl.html
+++ b/ui/src/app/dashboard/dashboard.tpl.html
@@ -136,7 +136,7 @@
</header-pane>
<div>
<md-tabs ng-if="vm.timeseriesWidgetTypes.length > 0 || vm.latestWidgetTypes.length > 0 ||
- vm.rpcWidgetTypes.length > 0"
+ vm.rpcWidgetTypes.length > 0 || vm.staticWidgetTypes.length > 0"
flex
class="tb-absolute-fill" md-border-bottom>
<md-tab ng-if="vm.timeseriesWidgetTypes.length > 0" style="height: 100%;" label="{{ 'widget.timeseries' | translate }}">
@@ -169,9 +169,19 @@
on-widget-clicked="vm.addWidgetFromType(event, widget)">
</tb-dashboard>
</md-tab>
+ <md-tab ng-if="vm.staticWidgetTypes.length > 0" style="height: 100%;" label="{{ 'widget.static' | translate }}">
+ <tb-dashboard
+ widgets="vm.staticWidgetTypes"
+ is-edit="false"
+ is-mobile="true"
+ is-edit-action-enabled="false"
+ is-remove-action-enabled="false"
+ on-widget-clicked="vm.addWidgetFromType(event, widget)">
+ </tb-dashboard>
+ </md-tab>
</md-tabs>
<span translate ng-if="vm.timeseriesWidgetTypes.length === 0 && vm.latestWidgetTypes.length === 0 &&
- vm.rpcWidgetTypes.length === 0 && vm.widgetsBundle"
+ vm.rpcWidgetTypes.length === 0 && vm.staticWidgetTypes.length === 0 && vm.widgetsBundle"
layout-align="center center"
style="text-transform: uppercase; display: flex;"
class="md-headline tb-absolute-fill">widgets-bundle.empty</span>
diff --git a/ui/src/app/device/attribute/attribute-table.directive.js b/ui/src/app/device/attribute/attribute-table.directive.js
index 63794dc..bec99ea 100644
--- a/ui/src/app/device/attribute/attribute-table.directive.js
+++ b/ui/src/app/device/attribute/attribute-table.directive.js
@@ -305,31 +305,33 @@ export default function AttributeTableDirective($compile, $templateCache, $rootS
for (var i = 0; i < widgetTypes.length; i++) {
var widgetType = widgetTypes[i];
var widgetInfo = widgetService.toWidgetInfo(widgetType);
- var sizeX = widgetInfo.sizeX*2;
- var sizeY = widgetInfo.sizeY*2;
- var col = Math.floor(Math.max(0, (20 - sizeX)/2));
- var widget = {
- isSystemType: isSystem,
- bundleAlias: bundleAlias,
- typeAlias: widgetInfo.alias,
- type: widgetInfo.type,
- title: widgetInfo.widgetName,
- sizeX: sizeX,
- sizeY: sizeY,
- row: 0,
- col: col,
- config: angular.fromJson(widgetInfo.defaultConfig)
- };
-
- widget.config.title = widgetInfo.widgetName;
- widget.config.datasources = [datasource];
- var length;
- if (scope.attributeScope === types.latestTelemetry && widgetInfo.type !== types.widgetType.rpc.value) {
- length = scope.widgetsListCache.push([widget]);
- scope.widgetsList.push(length === 1 ? [widget] : []);
- } else if (widgetInfo.type === types.widgetType.latest.value) {
- length = scope.widgetsListCache.push([widget]);
- scope.widgetsList.push(length === 1 ? [widget] : []);
+ if (widgetInfo.type !== types.widgetType.static.value) {
+ var sizeX = widgetInfo.sizeX * 2;
+ var sizeY = widgetInfo.sizeY * 2;
+ var col = Math.floor(Math.max(0, (20 - sizeX) / 2));
+ var widget = {
+ isSystemType: isSystem,
+ bundleAlias: bundleAlias,
+ typeAlias: widgetInfo.alias,
+ type: widgetInfo.type,
+ title: widgetInfo.widgetName,
+ sizeX: sizeX,
+ sizeY: sizeY,
+ row: 0,
+ col: col,
+ config: angular.fromJson(widgetInfo.defaultConfig)
+ };
+
+ widget.config.title = widgetInfo.widgetName;
+ widget.config.datasources = [datasource];
+ var length;
+ if (scope.attributeScope === types.latestTelemetry && widgetInfo.type !== types.widgetType.rpc.value) {
+ length = scope.widgetsListCache.push([widget]);
+ scope.widgetsList.push(length === 1 ? [widget] : []);
+ } else if (widgetInfo.type === types.widgetType.latest.value) {
+ length = scope.widgetsListCache.push([widget]);
+ scope.widgetsList.push(length === 1 ? [widget] : []);
+ }
}
}
scope.widgetsLoaded = true;
diff --git a/ui/src/app/help/help-links.constant.js b/ui/src/app/help/help-links.constant.js
index 0ce0395..62d6c2d 100644
--- a/ui/src/app/help/help-links.constant.js
+++ b/ui/src/app/help/help-links.constant.js
@@ -45,7 +45,7 @@ var pluginActionsClazzHelpLinkMap = {
'org.thingsboard.server.extensions.rest.action.RestApiCallPluginAction': 'pluginActionRestApiCall'
};
-var helpBaseUrl = "http://thingsboard.io";
+var helpBaseUrl = "https://thingsboard.io";
export default angular.module('thingsboard.help', [])
.constant('helpLinks',
@@ -86,6 +86,7 @@ export default angular.module('thingsboard.help', [])
widgetsConfigTimeseries: helpBaseUrl + "/docs/user-guide/ui/dashboards#timeseries",
widgetsConfigLatest: helpBaseUrl + "/docs/user-guide/ui/dashboards#latest",
widgetsConfigRpc: helpBaseUrl + "/docs/user-guide/ui/dashboards#rpc",
+ widgetsConfigStatic: helpBaseUrl + "/docs/user-guide/ui/dashboards#static",
},
getPluginLink: function(plugin) {
var link = 'plugins';
diff --git a/ui/src/app/widget/select-widget-type.tpl.html b/ui/src/app/widget/select-widget-type.tpl.html
index e7ada8b..1b39835 100644
--- a/ui/src/app/widget/select-widget-type.tpl.html
+++ b/ui/src/app/widget/select-widget-type.tpl.html
@@ -53,6 +53,13 @@
</md-icon>
<span translate>{{vm.types.widgetType.rpc.name}}</span>
</md-button>
+ <md-button class="tb-card-button md-raised md-primary" layout="column"
+ ng-click="vm.typeSelected(vm.types.widgetType.static.value)">
+ <md-icon class="material-icons tb-md-96"
+ aria-label="{{ vm.types.widgetType.static.name | translate }}">font_download
+ </md-icon>
+ <span translate>{{vm.types.widgetType.static.name}}</span>
+ </md-button>
</div>
</fieldset>
</div>
ui/src/locale/en_US.json 2(+2 -0)
diff --git a/ui/src/locale/en_US.json b/ui/src/locale/en_US.json
index cf1a97b..d9a761c 100644
--- a/ui/src/locale/en_US.json
+++ b/ui/src/locale/en_US.json
@@ -603,6 +603,7 @@
"timeseries": "Time series",
"latest-values": "Latest values",
"rpc": "Control widget",
+ "static": "Static widget",
"select-widget-type": "Select widget type",
"missing-widget-title-error": "Widget title must be specified!",
"widget-saved": "Widget saved",
@@ -663,6 +664,7 @@
"title": "Title",
"general-settings": "General settings",
"display-title": "Display title",
+ "drop-shadow": "Drop shadow",
"background-color": "Background color",
"text-color": "Text color",
"padding": "Padding",