Commit 9d33d5b4e500c0b783e835035ffc7bbbf0affcc9
Merge remote-tracking branch 'origin/develop/3.0' into feature/rest-client-improvement-3.0
Showing
85 changed files
with
1332 additions
and
1050 deletions
Too many changes to show.
To preserve performance only 85 of 1089 files are displayed.
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>application</artifactId> |
... | ... | @@ -116,7 +116,7 @@ |
116 | 116 | </dependency> |
117 | 117 | <dependency> |
118 | 118 | <groupId>org.thingsboard</groupId> |
119 | - <artifactId>ui</artifactId> | |
119 | + <artifactId>ui-ngx</artifactId> | |
120 | 120 | <version>${project.version}</version> |
121 | 121 | <scope>runtime</scope> |
122 | 122 | </dependency> | ... | ... |
... | ... | @@ -13,9 +13,9 @@ |
13 | 13 | "sizeX": 10.5, |
14 | 14 | "sizeY": 6.5, |
15 | 15 | "resources": [], |
16 | - "templateHtml": "<tb-alarms-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-alarms-table-widget>", | |
16 | + "templateHtml": "<tb-alarms-table-widget \n [ctx]=\"ctx\">\n</tb-alarms-table-widget>", | |
17 | 17 | "templateCss": "", |
18 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('alarms-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
18 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.alarmsTableWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"AlarmTableSettings\",\n \"properties\": {\n \"alarmsTitle\": {\n \"title\": \"Alarms table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSelection\": {\n \"title\": \"Enable alarms selection\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSearch\": {\n \"title\": \"Enable alarms search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStatusFilter\": {\n \"title\": \"Enable alarm status filter\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayDetails\": {\n \"title\": \"Display alarm details\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowAcknowledgment\": {\n \"title\": \"Allow alarms acknowledgment\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"allowClear\": {\n \"title\": \"Allow alarms clear\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"-createdTime\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"alarmsTitle\",\n \"enableSelection\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStatusFilter\",\n \"displayDetails\",\n \"allowAcknowledgment\",\n \"allowClear\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, alarm, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
21 | 21 | "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStatusFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{}}" | ... | ... |
... | ... | @@ -29,12 +29,12 @@ |
29 | 29 | "sizeX": 7.5, |
30 | 30 | "sizeY": 6.5, |
31 | 31 | "resources": [], |
32 | - "templateHtml": "<tb-entities-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-entities-table-widget>", | |
32 | + "templateHtml": "<tb-entities-table-widget \n [ctx]=\"ctx\">\n</tb-entities-table-widget>", | |
33 | 33 | "templateCss": "", |
34 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('entities-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
35 | - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityLabel\": {\n \"title\": \"Display entity label column\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"entityLabelColumnTitle\": {\n \"title\": \"Entity label column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ]\n}", | |
36 | - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", | |
37 | - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true,\"enableSelectColumnDisplay\":true},\"title\":\"Entity table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"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;\"}]}],\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{}}" | |
34 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
35 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"entitiesTitle\": {\n \"title\": \"Entities table title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"enableSearch\": {\n \"title\": \"Enable entities search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableSelectColumnDisplay\": {\n \"title\": \"Enable select columns to display\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayEntityName\": {\n \"title\": \"Display entity name column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"entityNameColumnTitle\": {\n \"title\": \"Entity name column title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"displayEntityType\": {\n \"title\": \"Display entity type column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultSortOrder\": {\n \"title\": \"Default sort order\",\n \"type\": \"string\",\n \"default\": \"entityName\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\"\n ]\n}", | |
36 | + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"columnWidth\": {\n \"title\": \"Column width (px or %)\",\n \"type\": \"string\",\n \"default\": \"0px\"\n },\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", | |
37 | + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"entityName\",\"displayEntityName\":true,\"displayEntityType\":true},\"title\":\"Entities table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"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;\"}]}]}" | |
38 | 38 | } |
39 | 39 | }, |
40 | 40 | { |
... | ... | @@ -63,7 +63,7 @@ |
63 | 63 | "resources": [], |
64 | 64 | "templateHtml": "", |
65 | 65 | "templateCss": "", |
66 | - "controllerScript": "self.onInit = function() {\n self.ctx.varsRegex = /\\$\\{([^\\}]*)\\}/g;\n self.ctx.htmlSet = false;\n \n var cssParser = new cssjs();\n cssParser.testMode = false;\n var namespace = 'html-value-card-' + hashCode(self.ctx.settings.cardCss);\n cssParser.cssPreviewNamespace = namespace;\n cssParser.createStyleElement(namespace, self.ctx.settings.cardCss);\n self.ctx.$container.addClass(namespace);\n var evtFnPrefix = 'htmlValueCard_' + Math.abs(hashCode(self.ctx.settings.cardCss + self.ctx.settings.cardHtml));\n self.ctx.html = '<div style=\"height:100%\" onclick=\"' + evtFnPrefix + '_onClickFn(event)\">' + \n self.ctx.settings.cardHtml + \n '</div>';\n\n self.ctx.replaceInfo = processHtmlPattern(self.ctx.html, self.ctx.data);\n \n updateHtml();\n \n window[evtFnPrefix + '_onClickFn'] = function (event) {\n self.ctx.actionsApi.elementClick(event);\n }\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 function processHtmlPattern(pattern, data) {\n var match = self.ctx.varsRegex.exec(pattern);\n var replaceInfo = {};\n replaceInfo.variables = [];\n while (match !== null) {\n var variableInfo = {};\n variableInfo.dataKeyIndex = -1;\n var variable = match[0];\n var label = match[1];\n var valDec = 2;\n var splitVals = label.split(':');\n if (splitVals.length > 1) {\n label = splitVals[0];\n valDec = parseFloat(splitVals[1]);\n }\n variableInfo.variable = variable;\n variableInfo.valDec = valDec;\n if (label == 'entityName') {\n variableInfo.isEntityName = true;\n } else if (label == 'entityLabel') {\n variableInfo.isEntityLabel = true;\n } else if (label.startsWith('#')) {\n var keyIndexStr = label.substring(1);\n var n = Math.floor(Number(keyIndexStr));\n if (String(n) === keyIndexStr && n >= 0) {\n variableInfo.dataKeyIndex = n;\n }\n }\n if (!variableInfo.isEntityName && !variableInfo.isEntityLabel && variableInfo.dataKeyIndex === -1) {\n for (var i = 0; i < data.length; i++) {\n var datasourceData = data[i];\n var dataKey = datasourceData.dataKey;\n if (dataKey.label === label) {\n variableInfo.dataKeyIndex = i;\n break;\n }\n }\n }\n replaceInfo.variables.push(variableInfo);\n match = self.ctx.varsRegex.exec(pattern);\n }\n return replaceInfo;\n } \n}\n\nself.onDataUpdated = function() {\n updateHtml();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.onDestroy = function() {\n}\n\nfunction isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n}\n\nfunction padValue(val, dec, int) {\n var i = 0;\n var s, strVal, n;\n\n val = parseFloat(val);\n n = (val < 0);\n val = Math.abs(val);\n\n if (dec > 0) {\n strVal = val.toFixed(dec).toString().split('.');\n s = int - strVal[0].length;\n\n for (; i < s; ++i) {\n strVal[0] = '0' + strVal[0];\n }\n\n strVal = (n ? '-' : '') + strVal[0] + '.' + strVal[1];\n }\n\n else {\n strVal = Math.round(val).toString();\n s = int - strVal.length;\n\n for (; i < s; ++i) {\n strVal = '0' + strVal;\n }\n\n strVal = (n ? '-' : '') + strVal;\n }\n\n return strVal;\n}\n\nfunction updateHtml() {\n var $injector = self.ctx.$scope.$injector;\n var utils = $injector.get('utils');\n var types = $injector.get('types');\n var text = self.ctx.html;\n var updated = false;\n for (var v in self.ctx.replaceInfo.variables) {\n var variableInfo = self.ctx.replaceInfo.variables[v];\n var txtVal = '';\n if (variableInfo.dataKeyIndex > -1) {\n var varData = self.ctx.data[variableInfo.dataKeyIndex].data;\n if (varData.length > 0) {\n var val = varData[varData.length-1][1];\n if (isNumber(val)) {\n txtVal = padValue(val, variableInfo.valDec, 0);\n } else {\n txtVal = val;\n }\n }\n } else if (variableInfo.isEntityName) {\n if (self.ctx.defaultSubscription.datasources.length) {\n txtVal = self.ctx.defaultSubscription.datasources[0].entityName;\n } else {\n txtVal = 'Unknown';\n }\n } else if (variableInfo.isEntityLabel) {\n if (self.ctx.defaultSubscription.datasources.length) {\n txtVal = self.ctx.defaultSubscription.datasources[0].entityLabel || self.ctx.defaultSubscription.datasources[0].entityName;\n } else {\n txtVal = 'Unknown';\n }\n }\n if (typeof variableInfo.lastVal === undefined ||\n variableInfo.lastVal !== txtVal) {\n updated = true;\n variableInfo.lastVal = txtVal;\n }\n text = text.split(variableInfo.variable).join(txtVal);\n }\n if (updated || !self.ctx.htmlSet) {\n text = replaceCustomTranslations(text);\n self.ctx.$container.html(text);\n if (!self.ctx.htmlSet) {\n self.ctx.htmlSet = true;\n }\n }\n \n function replaceCustomTranslations (pattern) {\n var customTranslationRegex = new RegExp('{' + types.translate.i18nPrefix + ':[^{}]+}', 'g');\n pattern = pattern.replace(customTranslationRegex, getTranslationText);\n return pattern;\n }\n \n function getTranslationText (variable) {\n return utils.customTranslation(variable, variable);\n \n }\n}\n\n", | |
66 | + "controllerScript": "self.onInit = function() {\n self.ctx.varsRegex = /\\$\\{([^\\}]*)\\}/g;\n self.ctx.htmlSet = false;\n \n var cssParser = new cssjs();\n cssParser.testMode = false;\n var namespace = 'html-value-card-' + hashCode(self.ctx.settings.cardCss);\n cssParser.cssPreviewNamespace = namespace;\n cssParser.createStyleElement(namespace, self.ctx.settings.cardCss);\n self.ctx.$container.addClass(namespace);\n var evtFnPrefix = 'htmlValueCard_' + Math.abs(hashCode(self.ctx.settings.cardCss + self.ctx.settings.cardHtml));\n self.ctx.html = '<div style=\"height:100%\" onclick=\"' + evtFnPrefix + '_onClickFn(event)\">' + \n self.ctx.settings.cardHtml + \n '</div>';\n\n self.ctx.replaceInfo = processHtmlPattern(self.ctx.html, self.ctx.data);\n \n updateHtml();\n \n window[evtFnPrefix + '_onClickFn'] = function (event) {\n self.ctx.actionsApi.elementClick(event);\n }\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 function processHtmlPattern(pattern, data) {\n var match = self.ctx.varsRegex.exec(pattern);\n var replaceInfo = {};\n replaceInfo.variables = [];\n while (match !== null) {\n var variableInfo = {};\n variableInfo.dataKeyIndex = -1;\n var variable = match[0];\n var label = match[1];\n var valDec = 2;\n var splitVals = label.split(':');\n if (splitVals.length > 1) {\n label = splitVals[0];\n valDec = parseFloat(splitVals[1]);\n }\n variableInfo.variable = variable;\n variableInfo.valDec = valDec;\n if (label == 'entityName') {\n variableInfo.isEntityName = true;\n } else if (label == 'entityLabel') {\n variableInfo.isEntityLabel = true;\n } else if (label.startsWith('#')) {\n var keyIndexStr = label.substring(1);\n var n = Math.floor(Number(keyIndexStr));\n if (String(n) === keyIndexStr && n >= 0) {\n variableInfo.dataKeyIndex = n;\n }\n }\n if (!variableInfo.isEntityName && !variableInfo.isEntityLabel && variableInfo.dataKeyIndex === -1) {\n for (var i = 0; i < data.length; i++) {\n var datasourceData = data[i];\n var dataKey = datasourceData.dataKey;\n if (dataKey.label === label) {\n variableInfo.dataKeyIndex = i;\n break;\n }\n }\n }\n replaceInfo.variables.push(variableInfo);\n match = self.ctx.varsRegex.exec(pattern);\n }\n return replaceInfo;\n } \n}\n\nself.onDataUpdated = function() {\n updateHtml();\n}\n\nself.actionSources = function() {\n return {\n 'elementClick': {\n name: 'widget-action.element-click',\n multiple: true\n }\n };\n}\n\nself.onDestroy = function() {\n}\n\nfunction isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n}\n\nfunction padValue(val, dec, int) {\n var i = 0;\n var s, strVal, n;\n\n val = parseFloat(val);\n n = (val < 0);\n val = Math.abs(val);\n\n if (dec > 0) {\n strVal = val.toFixed(dec).toString().split('.');\n s = int - strVal[0].length;\n\n for (; i < s; ++i) {\n strVal[0] = '0' + strVal[0];\n }\n\n strVal = (n ? '-' : '') + strVal[0] + '.' + strVal[1];\n }\n\n else {\n strVal = Math.round(val).toString();\n s = int - strVal.length;\n\n for (; i < s; ++i) {\n strVal = '0' + strVal;\n }\n\n strVal = (n ? '-' : '') + strVal;\n }\n\n return strVal;\n}\n\nfunction updateHtml() {\n var $injector = self.ctx.$scope.$injector;\n var utils = $injector.get(self.ctx.servicesMap.get('utils'));\n var text = self.ctx.html;\n var updated = false;\n for (var v in self.ctx.replaceInfo.variables) {\n var variableInfo = self.ctx.replaceInfo.variables[v];\n var txtVal = '';\n if (variableInfo.dataKeyIndex > -1) {\n var varData = self.ctx.data[variableInfo.dataKeyIndex].data;\n if (varData.length > 0) {\n var val = varData[varData.length-1][1];\n if (isNumber(val)) {\n txtVal = padValue(val, variableInfo.valDec, 0);\n } else {\n txtVal = val;\n }\n }\n } else if (variableInfo.isEntityName) {\n if (self.ctx.defaultSubscription.datasources.length) {\n txtVal = self.ctx.defaultSubscription.datasources[0].entityName;\n } else {\n txtVal = 'Unknown';\n }\n } else if (variableInfo.isEntityLabel) {\n if (self.ctx.defaultSubscription.datasources.length) {\n txtVal = self.ctx.defaultSubscription.datasources[0].entityLabel || self.ctx.defaultSubscription.datasources[0].entityName;\n } else {\n txtVal = 'Unknown';\n }\n }\n if (typeof variableInfo.lastVal === undefined ||\n variableInfo.lastVal !== txtVal) {\n updated = true;\n variableInfo.lastVal = txtVal;\n }\n text = text.split(variableInfo.variable).join(txtVal);\n }\n if (updated || !self.ctx.htmlSet) {\n text = replaceCustomTranslations(text);\n self.ctx.$container.html(text);\n if (!self.ctx.htmlSet) {\n self.ctx.htmlSet = true;\n }\n }\n \n function replaceCustomTranslations (pattern) {\n var customTranslationRegex = new RegExp('{i18n:[^{}]+}', 'g');\n pattern = pattern.replace(customTranslationRegex, getTranslationText);\n return pattern;\n }\n \n function getTranslationText (variable) {\n return utils.customTranslation(variable, variable);\n \n }\n}\n\n", | |
67 | 67 | "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}", |
68 | 68 | "dataKeySettingsSchema": "{}\n", |
69 | 69 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"My value\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"return Math.random() * 5.45;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"cardCss\":\".card {\\n width: 100%;\\n height: 100%;\\n border: 2px solid #ccc;\\n box-sizing: border-box;\\n}\\n\\n.card .content {\\n padding: 20px;\\n display: flex;\\n flex-direction: row;\\n align-items: center;\\n justify-content: space-around;\\n height: 100%;\\n box-sizing: border-box;\\n}\\n\\n.card .content .column {\\n display: flex;\\n flex-direction: column; \\n justify-content: space-around;\\n height: 100%;\\n}\\n\\n.card h1 {\\n text-transform: uppercase;\\n color: #999;\\n font-size: 20px;\\n font-weight: bold;\\n margin: 0;\\n padding-bottom: 10px;\\n line-height: 32px;\\n}\\n\\n.card .value {\\n font-size: 38px;\\n font-weight: 200;\\n}\\n\\n.card .description {\\n font-size: 20px;\\n color: #999;\\n}\\n\",\"cardHtml\":\"<div class='card'>\\n <div class='content'>\\n <div class='column'>\\n <h1>Value title</h1>\\n <div class='value'>\\n ${My value:2} units.\\n </div> \\n <div class='description'>\\n Value description text\\n </div>\\n </div>\\n <img height=\\\"80px\\\" src=\\\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMzIwIiB3aWR0aD0iMzIwIj48ZyBzdHJva2Utd2lkdGg9IjI4Ij48ZyBmaWxsPSIjMzA1NjgwIiBjb2xvcj0iIzAwMCIgd2hpdGUtc3BhY2U9Im5vcm1hbCI+PHBhdGggc3R5bGU9InRleHQtZGVjb3JhdGlvbi1jb2xvcjojMDAwO2lzb2xhdGlvbjphdXRvO21peC1ibGVuZC1tb2RlOm5vcm1hbDtibG9jay1wcm9ncmVzc2lvbjp0Yjt0ZXh0LWRlY29yYXRpb24tbGluZTpub25lO3RleHQtZGVjb3JhdGlvbi1zdHlsZTpzb2xpZDt0ZXh0LWluZGVudDowO3RleHQtdHJhbnNmb3JtOm5vbmUiIGQ9Ik0xNTEuMTMgMGMtMjguMzYzIDAtNTQuOTE1IDcuOTE1LTc3LjYxMyAyMS41MzdhMzYuNTc4IDM2LjU3OCAwIDAgMC0yMy4wNjctOC4xOTQgOC43NjYgOC43NjYgMCAwIDAtLjAwNCAwYy0yMC4xNTQuMDAxLTM2LjY3OSAxNi41MjgtMzYuNjc4IDM2LjY4MmE4Ljc2NiA4Ljc2NiAwIDAgMCAwIC4wMSAzNi42OSAzNi42OSAwIDAgMCA4LjEwNCAyMi45MjhjLTEzLjgzIDIyLjgzLTIxLjg3IDQ5LjU4LTIxLjg3IDc4LjE3YTguNzY2IDguNzY2IDAgMSAwIDE3LjUzIDBjMC0yNC43MDIgNi43Mi00Ny43NDggMTguMzc5LTY3LjU3NCA0LjU2NiAxLjk4NSA5LjQ3MiAzLjE1IDE0LjUxOSAzLjE1N2E4Ljc2NiA4Ljc2NiAwIDAgMCAuMDEyIDBjMjAuMTU1IDAgMzYuNjgzLTE2LjUyNyAzNi42ODItMzYuNjgyYTguNzY2IDguNzY2IDAgMCAwIDAtLjAwNGMtLjAwMS01LTEuMTM4LTkuODYzLTMuMDgzLTE0LjM5NyAxOS43MTctMTEuNDg0IDQyLjU4NS0xOC4wOTUgNjcuMDg1LTE4LjA5NWE4Ljc2NiA4Ljc2NiAwIDEgMCAwLTE3LjUzek01MC40NCAzMC44OGM1LjkxMy4wMDIgMTEuMTkxIDIuNTEyIDE0LjgzNiA3LjA3N2E4Ljc2NiA4Ljc2NiAwIDAgMCAuMTgzLjIxNCAxOS4xMzcgMTkuMTM3IDAgMCAxIDQuMTM0IDExLjg2M2MtLjAwMiAxMC42NzctOC40NjggMTkuMTQ0LTE5LjE0NCAxOS4xNDhhMTkuMTQ1IDE5LjE0NSAwIDAgMS0xMi00LjI1NCA4Ljc2NiA4Ljc2NiAwIDAgMC0uMDEzLS4wMSAxOS4xMzYgMTkuMTM2IDAgMCAxLTcuMTQ0LTE0Ljg5MmMuMDAzLTEwLjY3NyA4LjQ3LTE5LjE0NCAxOS4xNDgtMTkuMTQ2eiIvPjxwYXRoIHN0eWxlPSJ0ZXh0LWRlY29yYXRpb24tY29sb3I6IzAwMDtpc29sYXRpb246YXV0bzttaXgtYmxlbmQtbW9kZTpub3JtYWw7YmxvY2stcHJvZ3Jlc3Npb246dGI7dGV4dC1kZWNvcmF0aW9uLWxpbmU6bm9uZTt0ZXh0LWRlY29yYXRpb24tc3R5bGU6c29saWQ7dGV4dC1pbmRlbnQ6MDt0ZXh0LXRyYW5zZm9ybTpub25lIiBkPSJNNjYuOTkyIDEwMi44M2E4LjE4NyA4LjE4NyAwIDAgMC0yLjI1OCA2LjA3MSA4LjYwNCA4LjYwNCAwIDAgMCAyLjMzOCA1LjUxOGM2LjgwNSA2Ljg1NiAyMC4yMjMgMjAuMjIzIDIwLjIyMyAyMC4yMjNsMTEuODQ0LTExLjgzcy0xMi45NzMtMTIuOTYxLTIwLjE3Ni0yMC4xNzFjLTEuNjA0LTEuNjMyLTMuNzUtMi4zMTQtNi4wMTItMi4zMjRhOC4xNSA4LjE1IDAgMCAwLTUuOTYgMi41MTJ6bTMyLjE0NyAxOS45ODNMNjIuNSAxNTkuNDUyYy0zLjk3NSAzLjk3Ni0zLjk3NSAxMC40MjEgMCAxNC4zOTdsMTguMTU2IDE4LjE1NiAzMS43NTMgMzEuNzUzIDMwLjQ3OCAzMC40NzhjMy45NzYgMy45NzYgMTAuNDIyIDMuOTc2IDE0LjM5OCAwbDI0Ljc5MS0yNC43OTEgMzcuOTE0LTM3LjkxNCAzNi42MzktMzYuNjM5YzMuOTc1LTMuOTc2IDMuOTc1LTEwLjQyMiAwLTE0LjM5OGwtMTguNjMtMTguNjMtMzEuNzUtMzEuNzYtMzAuMDEtMzBjLTMuOTc3LTMuOTc1LTEwLjQyMi0zLjk3NS0xNC4zOTggMGwtMjQuNzkgMjQuNzktMzcuOTEgMzcuOTF6bTM3LjkxMS0zNy45MXMtMTIuOTczLTEyLjk2MS0yMC4xNzYtMjAuMTcxYy0xLjYwNC0xLjYzMi0zLjc1LTIuMzE0LTYuMDEyLTIuMzI0LTQuNzE3LS4wMjMtOC40MzQgMy44NjEtOC4yMTcgOC41ODNhOC42MDQgOC42MDQgMCAwIDAgMi4zMzcgNS41MThjNi44MDUgNi44NTYgMjAuMjIzIDIwLjIyMyAyMC4yMjMgMjAuMjIzbDExLjg0NC0xMS44M3ptNjkuMTkzIDUuMjEzczEyLjk2MS0xMi45NzMgMjAuMTcxLTIwLjE3NmMxLjYzMy0xLjYwNCAyLjMxNC0zLjc1IDIuMzI0LTYuMDEyLjAyMy00LjcxNi0zLjg2MS04LjQzNC04LjU4My04LjIxN2E4LjYwNCA4LjYwNCAwIDAgMC01LjUxOCAyLjMzOGMtNi44NTYgNi44MDUtMjAuMjIzIDIwLjIyMy0yMC4yMjMgMjAuMjIzbDExLjgzIDExLjg0NHptMzEuNzUzIDMxLjc1M3MxMi45NjEtMTIuOTczIDIwLjE3MS0yMC4xNzZjMS42MzMtMS42MDQgMi4zMTQtMy43NSAyLjMyNC02LjAxMi4wMjMtNC43MTYtMy44NjEtOC40MzQtOC41ODMtOC4yMTdhOC42MDQgOC42MDQgMCAwIDAtNS41MTggMi4zMzhjLTYuODU2IDYuODA1LTIwLjIyMyAyMC4yMjMtMjAuMjIzIDIwLjIyM2wxMS44MyAxMS44NDR6bS0xOC4wMDkgNjkuNjY3czEyLjk3MyAxMi45NjEgMjAuMTc4IDIwLjE3YzEuNjA0IDEuNjMyIDMuNzUgMi4zMTMgNi4wMTIgMi4zMjQgNC43MTcuMDIyIDguNDM0LTMuODYyIDguMjE3LTguNTg0bC0uMDAyLjAwMmE4LjYwNiA4LjYwNiAwIDAgMC0yLjMzOC01LjUxOGMtNi44MDUtNi44NTYtMjAuMjIyLTIwLjIyMi0yMC4yMjItMjAuMjIybC0xMS44NDQgMTEuODN6bS0zNy45MTQgMzcuOTE0czEyLjk3MyAxMi45NjEgMjAuMTc4IDIwLjE3YzEuNjA0IDEuNjMyIDMuNzUgMi4zMTMgNi4wMTIgMi4zMjMgNC43MTcuMDIzIDguNDM0LTMuODYxIDguMjE3LTguNTgzaC0uMDAyYTguNjAzIDguNjAzIDAgMCAwLTIuMzM3LTUuNTE4Yy02LjgwNS02Ljg1Ni0yMC4yMjMtMjAuMjIzLTIwLjIyMy0yMC4yMjNsLTExLjg0NCAxMS44M3ptLTY5LjY2Ny01LjY4N3MtMTIuOTYxIDEyLjk3My0yMC4xNjkgMjAuMTc4Yy0xLjYzMiAxLjYwNC0yLjMxNCAzLjc1LTIuMzI0IDYuMDEyLS4wMjMgNC43MTcgMy44NjEgOC40MzQgOC41ODMgOC4yMTdoLS4wMDJhOC42MDIgOC42MDIgMCAwIDAgNS41MTgtMi4zMzdjNi44NTYtNi44MDUgMjAuMjIzLTIwLjIyMyAyMC4yMjMtMjAuMjIzbC0xMS44Mi0xMS44NHptLTMxLjc0My0zMS43NHMtMTIuOTYxIDEyLjk3My0yMC4xNjkgMjAuMTc4Yy0xLjYzMiAxLjYwNC0yLjMxNCAzLjc1LTIuMzI0IDYuMDEyLS4wMjMgNC43MTcgMy44NjEgOC40MzQgOC41ODMgOC4yMTdoLS4wMDJhOC42MDQgOC42MDQgMCAwIDAgNS41MTgtMi4zMzdjNi44NTYtNi44MDUgMjAuMjIzLTIwLjIyMyAyMC4yMjMtMjAuMjIzbC0xMS44My0xMS44NXpNMTY3LjkgMTAxLjQ3YzEuNjgtMS43MDYgMy45NjctMi42NiA2LjI5Ny0yLjYyNmE3Ljg5IDcuODkgMCAwIDEgNC41NjMgMS41MWwxNi40OTkgMTIuMWMzLjIgMi4yOTcgNC4xNDQgNi42NTkgMi4yMyAxMC4zMTItMS45MTMgMy42NTMtNi4xMjMgNS41MjQtOS45NSA0LjQyM2w2LjEyNCAyMy45NDhjMS4xMTMgNC4zNTEtMS41NjQgOC45NjctNS45ODQgMTAuMzE3bC00NC42NDIgMTMuNjMgOC4yNDYgMzEuODg0YzEuMTczIDQuMzctMS41MDIgOS4wNDQtNS45NTUgMTAuNDA3cy04Ljk3NS0xLjExMS0xMC4wNjgtNS41MDVsLTEwLjI4Mi0zOS43N2MtMS4xMjYtNC4zNTUgMS41NS04Ljk4NCA1Ljk3Ni0xMC4zMzdsNDQuNjYxLTEzLjYzNy00LjEyMi0xNi4xMThjLTIuNzYzIDMuMDY0LTcuMjMzIDMuODA4LTEwLjU4NiAxLjc2MS0zLjM1My0yLjA0Ny00LjYxNC02LjI5LTIuOTg2LTEwLjA0N2w4LjExNy0xOS40NTRhOC44NzIgOC44NzIgMCAwIDEgMS44NjMtMi43OTd6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBzdHlsZT0idGV4dC1kZWNvcmF0aW9uLWNvbG9yOiMwMDA7aXNvbGF0aW9uOmF1dG87bWl4LWJsZW5kLW1vZGU6bm9ybWFsO2Jsb2NrLXByb2dyZXNzaW9uOnRiO3RleHQtZGVjb3JhdGlvbi1saW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uLXN0eWxlOnNvbGlkO3RleHQtaW5kZW50OjA7dGV4dC10cmFuc2Zvcm06bm9uZSIgZD0iTTE2OC44NyAzMjAuMDRjMjguMzYzIDAgNTQuOTE1LTcuOTE1IDc3LjYxNC0yMS41MzhhMzYuNTc4IDM2LjU3OCAwIDAgMCAyMy4wNjcgOC4xOTQgOC43NjYgOC43NjYgMCAwIDAgLjAwNCAwYzIwLjE1NSAwIDM2LjY4LTE2LjUyOCAzNi42NzktMzYuNjgyYTguNzY2IDguNzY2IDAgMCAwIDAtLjAxMSAzNi42ODggMzYuNjg4IDAgMCAwLTguMTAzLTIyLjkyN2MxMy44MjUtMjIuODIgMjEuODY2LTQ5LjU3MiAyMS44NjYtNzguMTYyYTguNzY2IDguNzY2IDAgMSAwLTE3LjUzMSAwYzAgMjQuNzAzLTYuNzIgNDcuNzQ5LTE4LjM3OCA2Ny41NzUtNC41NjctMS45ODUtOS40NzMtMy4xNS0xNC41Mi0zLjE1N2E4Ljc2NiA4Ljc2NiAwIDAgMC0uMDEyIDBjLTIwLjE1NS0uMDAxLTM2LjY4MyAxNi41MjctMzYuNjgyIDM2LjY4Mi4wMDIgNC45OTkgMS4xMzkgOS44NjIgMy4wODMgMTQuMzk3LTE5LjcxNyAxMS40ODQtNDIuNTg2IDE4LjA5NS02Ny4wODYgMTguMDk1YTguNzY2IDguNzY2IDAgMSAwIDAgMTcuNTN6bTEwMC42OS0zMC44NzVjLTUuOTEzIDAtMTEuMTkxLTIuNTEyLTE0LjgzNi03LjA3N2E4Ljc2NiA4Ljc2NiAwIDAgMC0uMTgzLS4yMTQgMTkuMTM2IDE5LjEzNiAwIDAgMS00LjEzNC0xMS44NjNjLjAwMi0xMC42NzcgOC40NjgtMTkuMTQ0IDE5LjE0NC0xOS4xNDhhMTkuMTQ1IDE5LjE0NSAwIDAgMSAxMiA0LjI1NCA4Ljc2NiA4Ljc2NiAwIDAgMCAuMDEzLjAxIDE5LjEzNiAxOS4xMzYgMCAwIDEgNy4xNDQgMTQuODkyYy0uMDAzIDEwLjY3Ny04LjQ3IDE5LjE0NS0xOS4xNDggMTkuMTQ2eiIvPjwvZz48L2c+PC9zdmc+\\\" />\\n </div>\\n</div>\"},\"title\":\"HTML Value Card\",\"dropShadow\":false,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -109,12 +109,12 @@ |
109 | 109 | "sizeX": 8, |
110 | 110 | "sizeY": 6.5, |
111 | 111 | "resources": [], |
112 | - "templateHtml": "<tb-timeseries-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-timeseries-table-widget>", | |
112 | + "templateHtml": "<tb-timeseries-table-widget \n [ctx]=\"ctx\">\n</tb-timeseries-table-widget>", | |
113 | 113 | "templateCss": "", |
114 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.tableId = \"table-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('timeseries-table-data-updated', self.ctx.$scope.tableId);\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}", | |
114 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}", | |
115 | 115 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"showTimestamp\": {\n \"title\": \"Display timestamp column\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showMilliseconds\": {\n \"title\": \"Display timestamp milliseconds\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"displayPagination\": {\n \"title\": \"Display pagination\",\n \"type\": \"boolean\",\n \"default\": true\n }, \n \"defaultPageSize\": {\n \"title\": \"Default page size\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"hideEmptyLines\": {\n \"title\": \"Hide empty lines\",\n \"type\": \"boolean\",\n \"default\": false\n }\n },\n \"required\": []\n },\n \"form\": [\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"hideEmptyLines\"\n ]\n}", |
116 | - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, filter)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", | |
117 | - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}" | |
116 | + "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {\n \"useCellStyleFunction\": {\n \"title\": \"Use cell style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellStyleFunction\": {\n \"title\": \"Cell style function: f(value)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"useCellContentFunction\": {\n \"title\": \"Use cell content function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"cellContentFunction\": {\n \"title\": \"Cell content function: f(value, rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", | |
117 | + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', amount = percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\"},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\"}" | |
118 | 118 | } |
119 | 119 | }, |
120 | 120 | { |
... | ... | @@ -125,13 +125,13 @@ |
125 | 125 | "sizeX": 7.5, |
126 | 126 | "sizeY": 3.5, |
127 | 127 | "resources": [], |
128 | - "templateHtml": "<tb-entities-hierarchy-widget \n hierarchy-id=\"hierarchyId\"\n ctx=\"ctx\">\n</tb-entities-hierarchy-widget>", | |
128 | + "templateHtml": "<tb-entities-hierarchy-widget \n [ctx]=\"ctx\">\n</tb-entities-hierarchy-widget>", | |
129 | 129 | "templateCss": "", |
130 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n var id = self.ctx.$scope.$injector.get('utils').guid();\n scope.hierarchyId = \"hierarchy-\"+id;\n scope.ctx = self.ctx;\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.$broadcast('entities-hierarchy-data-updated', self.ctx.$scope.hierarchyId);\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'nodeSelected': {\n name: 'widget-action.node-selected',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
130 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesHierarchyWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'nodeSelected': {\n name: 'widget-action.node-selected',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", | |
131 | 131 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesHierarchySettings\",\n \"properties\": {\n \"nodeRelationQueryFunction\": {\n \"title\": \"Node relations query function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeHasChildrenFunction\": {\n \"title\": \"Node has children function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeOpenedFunction\": {\n \"title\": \"Default node opened function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeDisabledFunction\": {\n \"title\": \"Node disabled function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeIconFunction\": {\n \"title\": \"Node icon function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeTextFunction\": {\n \"title\": \"Node text function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodesSortFunction\": {\n \"title\": \"Nodes sort function: f(nodeCtx1, nodeCtx2)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"nodeRelationQueryFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeHasChildrenFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeOpenedFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeDisabledFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeIconFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeTextFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodesSortFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
132 | 132 | "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {},\n \"required\": []\n },\n \"form\": []\n}", |
133 | 133 | "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"nodeRelationQueryFunction\":\"/**\\n\\n// Function should return relations query object for current node used to fetch entity children.\\n// Function can return 'default' string value. In this case default relations query will be used.\\n\\n// The following example code will construct simple relations query that will fetch relations of type 'Contains'\\n// from the current entity.\\n\\nvar entity = nodeCtx.entity;\\nvar query = {\\n parameters: {\\n rootId: entity.id.id,\\n rootType: entity.id.entityType,\\n direction: types.entitySearchDirection.from,\\n relationTypeGroup: \\\"COMMON\\\",\\n maxLevel: 1\\n },\\n filters: [{\\n relationType: \\\"Contains\\\",\\n entityTypes: []\\n }]\\n};\\nreturn query;\\n\\n**/\\n\",\"nodeHasChildrenFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node has children (whether it can be expanded).\\n\\n// The following example code will restrict entities hierarchy expansion up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n// The next example code will restrict entities expansion according to the value of example 'nodeHasChildren' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeHasChildren') && data['nodeHasChildren'] !== null) {\\n return data['nodeHasChildren'] === 'true';\\n} else {\\n return true;\\n}\\n \\n**/\\n \",\"nodeTextFunction\":\"/**\\n\\n// Function should return text (can be HTML code) for the current node.\\n\\n// The following example code will generate node text consisting of entity name and temperature if temperature value is present in entity attributes/timeseries.\\n\\nvar data = nodeCtx.data;\\nvar entity = nodeCtx.entity;\\nvar text = entity.name;\\nif (data.hasOwnProperty('temperature') && data['temperature'] !== null) {\\n text += \\\" <b>\\\"+ data['temperature'] +\\\" °C</b>\\\";\\n}\\nreturn text;\\n\\n**/\",\"nodeIconFunction\":\"/** \\n\\n// Function should return node icon info object.\\n// Resulting object should contain either 'materialIcon' or 'iconUrl' property. \\n// Where:\\n - 'materialIcon' - name of the material icon to be used from the Material Icons Library (https://material.io/tools/icons);\\n - 'iconUrl' - url of the external image to be used as node icon.\\n// Function can return 'default' string value. In this case default icons according to entity type will be used.\\n\\n// The following example code shows how to use external image for devices which name starts with 'Test' and use \\n// default icons for the rest of entities.\\n\\nvar entity = nodeCtx.entity;\\nif (entity.id.entityType === 'DEVICE' && entity.name.startsWith('Test')) {\\n return {iconUrl: 'https://avatars1.githubusercontent.com/u/14793288?v=4&s=117'};\\n} else {\\n return 'default';\\n}\\n \\n**/\",\"nodeDisabledFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be disabled (not selectable).\\n\\n// The following example code will disable current node according to the value of example 'nodeDisabled' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeDisabled') && data['nodeDisabled'] !== null) {\\n return data['nodeDisabled'] === 'true';\\n} else {\\n return false;\\n}\\n \\n**/\\n\",\"nodesSortFunction\":\"/**\\n\\n// This function is used to sort nodes of the same level. Function should compare two nodes and return \\n// integer value: \\n// - less than 0 - sort nodeCtx1 to an index lower than nodeCtx2\\n// - 0 - leave nodeCtx1 and nodeCtx2 unchanged with respect to each other\\n// - greater than 0 - sort nodeCtx2 to an index lower than nodeCtx1\\n\\n// The following example code will sort entities first by entity type in alphabetical order then\\n// by entity name in alphabetical order.\\n\\nvar result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);\\nif (result === 0) {\\n result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name);\\n}\\nreturn result;\\n \\n**/\",\"nodeOpenedFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be opened (expanded) when it first loaded.\\n\\n// The following example code will open by default nodes up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n**/\\n \"},\"title\":\"Entities hierarchy\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"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;\"}]}],\"widgetStyle\":{},\"actions\":{}}" |
134 | 134 | } |
135 | 135 | } |
136 | 136 | ] |
137 | -} | |
137 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -55,7 +55,7 @@ |
55 | 55 | ], |
56 | 56 | "templateHtml": "<canvas id=\"pieChart\"></canvas>\n", |
57 | 57 | "templateCss": "", |
58 | - "controllerScript": "self.onInit = function() {\n var pieData = {\n labels: [],\n datasets: []\n };\n\n var dataset = {\n data: [],\n backgroundColor: [],\n borderColor: [],\n borderWidth: [],\n hoverBackgroundColor: []\n }\n \n var borderColor = self.ctx.settings.borderColor || '#fff';\n var borderWidth = angular.isDefined(self.ctx.settings.borderWidth) ? self.ctx.settings.borderWidth : 5;\n \n pieData.datasets.push(dataset);\n \n for (var i=0; i < self.ctx.data.length; i++) {\n var dataKey = self.ctx.data[i].dataKey;\n pieData.labels.push(dataKey.label);\n dataset.data.push(0);\n var hoverBackgroundColor = tinycolor(dataKey.color).lighten(15);\n dataset.backgroundColor.push(dataKey.color);\n dataset.borderColor.push(borderColor);\n dataset.borderWidth.push(borderWidth);\n dataset.hoverBackgroundColor.push(hoverBackgroundColor.toRgbString());\n }\n\n var options = {\n responsive: false,\n maintainAspectRatio: false,\n legend: {\n display: true,\n labels: {\n fontColor: '#666'\n }\n },\n tooltips: {\n callbacks: {\n label: function(tooltipItem, data) {\n var label = data.labels[tooltipItem.index];\n var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];\n var content = label + ': ' + value;\n var units = self.ctx.settings.units ? self.ctx.settings.units : self.ctx.units;\n if (units) {\n content += ' ' + units;\n } \n return content;\n }\n }\n }\n };\n\n if (self.ctx.settings.legend) {\n options.legend.display = self.ctx.settings.legend.display !== false;\n options.legend.labels.fontColor = self.ctx.settings.legend.labelsFontColor || '#666';\n }\n\n var ctx = $('#pieChart', self.ctx.$container);\n self.ctx.chart = new Chart(ctx, {\n type: 'doughnut',\n data: pieData,\n options: options\n });\n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.data.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n var value = tvPair[1];\n self.ctx.chart.data.datasets[0].data[i] = parseFloat(value);\n }\n }\n self.ctx.chart.update();\n}\n\nself.onResize = function() {\n self.ctx.chart.resize();\n}\n\n", | |
58 | + "controllerScript": "self.onInit = function() {\n var pieData = {\n labels: [],\n datasets: []\n };\n\n var dataset = {\n data: [],\n backgroundColor: [],\n borderColor: [],\n borderWidth: [],\n hoverBackgroundColor: []\n }\n \n var borderColor = self.ctx.settings.borderColor || '#fff';\n var borderWidth = typeof self.ctx.settings.borderWidth !== 'undefined' ? self.ctx.settings.borderWidth : 5;\n \n pieData.datasets.push(dataset);\n \n for (var i=0; i < self.ctx.data.length; i++) {\n var dataKey = self.ctx.data[i].dataKey;\n pieData.labels.push(dataKey.label);\n dataset.data.push(0);\n var hoverBackgroundColor = tinycolor(dataKey.color).lighten(15);\n dataset.backgroundColor.push(dataKey.color);\n dataset.borderColor.push(borderColor);\n dataset.borderWidth.push(borderWidth);\n dataset.hoverBackgroundColor.push(hoverBackgroundColor.toRgbString());\n }\n\n var options = {\n responsive: false,\n maintainAspectRatio: false,\n legend: {\n display: true,\n labels: {\n fontColor: '#666'\n }\n },\n tooltips: {\n callbacks: {\n label: function(tooltipItem, data) {\n var label = data.labels[tooltipItem.index];\n var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];\n var content = label + ': ' + value;\n var units = self.ctx.settings.units ? self.ctx.settings.units : self.ctx.units;\n if (units) {\n content += ' ' + units;\n } \n return content;\n }\n }\n }\n };\n\n if (self.ctx.settings.legend) {\n options.legend.display = self.ctx.settings.legend.display !== false;\n options.legend.labels.fontColor = self.ctx.settings.legend.labelsFontColor || '#666';\n }\n\n var ctx = $('#pieChart', self.ctx.$container);\n self.ctx.chart = new Chart(ctx, {\n type: 'doughnut',\n data: pieData,\n options: options\n });\n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.data.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n var value = tvPair[1];\n self.ctx.chart.data.datasets[0].data[i] = parseFloat(value);\n }\n }\n self.ctx.chart.update();\n}\n\nself.onResize = function() {\n self.ctx.chart.resize();\n}\n\n", | |
59 | 59 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"borderWidth\": {\n \"title\": \"Border width\",\n \"type\": \"number\",\n \"default\": 5\n },\n \"borderColor\": {\n \"title\": \"Border color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"legend\": {\n \"title\": \"Legend settings\",\n \"type\": \"object\",\n \"properties\": {\n \"display\": {\n \"title\": \"Display legend\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"labelsFontColor\": {\n \"title\": \"Labels font color\",\n \"type\": \"string\",\n \"default\": \"#666\"\n }\n }\n }\n },\n \"required\": []\n },\n \"form\": [\n \"borderWidth\", \n {\n \"key\": \"borderColor\",\n \"type\": \"color\"\n }, \n {\n \"key\": \"legend\",\n \"items\": [\n \"legend.display\",\n {\n \"key\": \"legend.labelsFontColor\",\n \"type\": \"color\"\n }\n ]\n }\n ]\n}", |
60 | 60 | "dataKeySettingsSchema": "{}\n", |
61 | 61 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#26a69a\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#f57c00\",\"settings\":{},\"_hash\":0.545701115289893,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#afb42b\",\"settings\":{},\"_hash\":0.2592906835158064,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#673ab7\",\"settings\":{},\"_hash\":0.12880275585455747,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"borderWidth\":5,\"borderColor\":\"#fff\",\"legend\":{\"display\":true,\"labelsFontColor\":\"#666666\"}},\"title\":\"Doughnut - Chart.js\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}" | ... | ... |
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | "resources": [], |
16 | 16 | "templateHtml": "<div style=\"height: 100%; overflow-y: auto;\" id=\"device-terminal\"></div>", |
17 | 17 | "templateCss": ".cmd .cursor.blink {\n -webkit-animation-name: terminal-underline;\n -moz-animation-name: terminal-underline;\n -ms-animation-name: terminal-underline;\n animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n border-bottom-color: #aaa;\n}\n", |
18 | - "controllerScript": "var requestTimeout = 500;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n var rpcEnabled = subscription.rpcEnabled;\n var deviceName = 'Simulated';\n var prompt;\n if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n deviceName = subscription.targetDeviceName;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n var greetings = 'Welcome to ThingsBoard RPC debug terminal.\\n\\n';\n if (!rpcEnabled) {\n greetings += 'Target device is not set!\\n\\n';\n prompt = '';\n } else {\n greetings += 'Current target device for RPC commands: [[b;#fff;]' + deviceName + ']\\n\\n';\n greetings += 'Please type [[b;#fff;]\\'help\\'] to see usage.\\n';\n prompt = '[[b;#8bc34a;]' + deviceName +']> ';\n }\n \n var terminal = $('#device-terminal', self.ctx.$container).terminal(\n function(command) {\n if (command !== '') {\n try {\n var localCommand = angular.copy(command).trim();\n if (localCommand == 'help') {\n printUsage(this);\n } else {\n var cmdObj = $.terminal.parse_command(localCommand);\n if (cmdObj.args.length > 1) {\n this.error(\"Wrong number of arguments!\");\n this.echo(' ');\n } else {\n var params;\n if (cmdObj.args.length && cmdObj.args[0]) {\n try {\n params = JSON.parse(cmdObj.args[0]);\n } catch (e) {\n params = cmdObj.args[0];\n }\n }\n performRpc(this, cmdObj.name, params);\n }\n }\n } catch(e) {\n this.error(new String(e));\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: greetings,\n prompt: prompt\n });\n \n if (!rpcEnabled) {\n terminal.error('No RPC target detected!').pause();\n }\n}\n\n\nfunction printUsage(terminal) {\n var commandsListText = '\\n[[b;#fff;]Usage:]\\n';\n commandsListText += ' <method> [params body]\\n\\n';\n commandsListText += '[[b;#fff;]Example 1:]\\n'; \n commandsListText += ' myRemoteMethod1 myText\\n\\n'; \n commandsListText += '[[b;#fff;]Example 2:]\\n'; \n commandsListText += ' myOtherRemoteMethod \"{\\\\\"key1\\\\\": 2, \\\\\"key2\\\\\": \\\\\"myVal\\\\\"}\"\\n'; \n terminal.echo(new String(commandsListText));\n}\n\nfunction performRpc(terminal, method, params) {\n terminal.pause();\n self.ctx.controlApi.sendTwoWayCommand(method, params, requestTimeout).then(\n function success(responseBody) {\n terminal.echo(JSON.stringify(responseBody));\n terminal.echo(' ');\n terminal.resume();\n },\n function fail() {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.echo(' ');\n terminal.resume();\n }\n );\n}\n\n \nself.onDestroy = function() {\n}\n", | |
18 | + "controllerScript": "var requestTimeout = 500;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n var rpcEnabled = subscription.rpcEnabled;\n var deviceName = 'Simulated';\n var prompt;\n if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n deviceName = subscription.targetDeviceName;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n var greetings = 'Welcome to ThingsBoard RPC debug terminal.\\n\\n';\n if (!rpcEnabled) {\n greetings += 'Target device is not set!\\n\\n';\n prompt = '';\n } else {\n greetings += 'Current target device for RPC commands: [[b;#fff;]' + deviceName + ']\\n\\n';\n greetings += 'Please type [[b;#fff;]\\'help\\'] to see usage.\\n';\n prompt = '[[b;#8bc34a;]' + deviceName +']> ';\n }\n \n var terminal = $('#device-terminal', self.ctx.$container).terminal(\n function(command) {\n if (command !== '') {\n try {\n var localCommand = command.trim();\n if (localCommand === 'help') {\n printUsage(this);\n } else {\n var cmdObj = $.terminal.parse_command(localCommand);\n if (cmdObj.args.length > 1) {\n this.error(\"Wrong number of arguments!\");\n this.echo(' ');\n } else {\n var params;\n if (cmdObj.args.length && cmdObj.args[0]) {\n try {\n params = JSON.parse(cmdObj.args[0]);\n } catch (e) {\n params = cmdObj.args[0];\n }\n }\n performRpc(this, cmdObj.name, params);\n }\n }\n } catch(e) {\n this.error(new String(e));\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: greetings,\n prompt: prompt,\n enabled: rpcEnabled\n });\n \n \n \n if (!rpcEnabled) {\n terminal.error('No RPC target detected!').pause();\n }\n}\n\n\nfunction printUsage(terminal) {\n var commandsListText = '\\n[[b;#fff;]Usage:]\\n';\n commandsListText += ' <method> [params body]]\\n\\n';\n commandsListText += '[[b;#fff;]Example 1:]\\n'; \n commandsListText += ' myRemoteMethod1 myText\\n\\n'; \n commandsListText += '[[b;#fff;]Example 2:]\\n'; \n commandsListText += ' myOtherRemoteMethod \"{\\\\\"key1\\\\\": 2, \\\\\"key2\\\\\": \\\\\"myVal\\\\\"}\"\\n'; \n terminal.echo(new String(commandsListText));\n}\n\nfunction performRpc(terminal, method, params) {\n terminal.pause();\n self.ctx.controlApi.sendTwoWayCommand(method, params, requestTimeout).subscribe(\n function success(responseBody) {\n terminal.echo(JSON.stringify(responseBody));\n terminal.echo(' ');\n terminal.resume();\n },\n function fail() {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.echo(' ');\n terminal.resume();\n }\n );\n}\n\n \nself.onDestroy = function() {\n}\n", | |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"requestTimeout\"\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{}\n", |
21 | 21 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#010101\",\"color\":\"rgba(255, 254, 254, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"RPC debug terminal\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | "resources": [], |
32 | 32 | "templateHtml": "<div style=\"height: 100%; overflow-y: auto;\" id=\"device-terminal\"></div>", |
33 | 33 | "templateCss": ".cmd .cursor.blink {\n -webkit-animation-name: terminal-underline;\n -moz-animation-name: terminal-underline;\n -ms-animation-name: terminal-underline;\n animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n border-bottom-color: #aaa;\n}\n", |
34 | - "controllerScript": "var requestTimeout = 500;\nconst commandStatusPollingInterval = 200;\n\nconst welcome = 'Welcome to ThingsBoard RPC remote shell.\\n';\n\nvar terminal, rpcEnabled, simulated, deviceName, cwd;\nvar commandExecuting = false;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n rpcEnabled = subscription.rpcEnabled;\n if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n deviceName = subscription.targetDeviceName;\n } else {\n deviceName = 'Simulated';\n simulated = true;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n \n terminal = $('#device-terminal', self.ctx.$container).terminal(\n function (command) {\n if (command && command.trim().length) {\n try {\n if (simulated) {\n this.echo(command);\n } else {\n sendCommand(this, command);\n }\n } catch(e) {\n this.error(new String(e));\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: false,\n prompt: rpcEnabled ? currentPrompt : '',\n name: 'shell',\n pauseEvents: false,\n keydown: (e, term) => {\n if ((e.which == 67 || e.which == 68) && e.ctrlKey) { // CTRL+C || CTRL+D\n if (commandExecuting) {\n terminateCommand(term);\n return false;\n }\n }\n },\n onInit: initTerm\n }\n );\n}\n\nfunction initTerm(terminal) {\n terminal.echo(welcome);\n if (!rpcEnabled) {\n terminal.error('Target device is not set!\\n');\n } else {\n terminal.echo(`Current target device for RPC terminal: [[b;#fff;]${deviceName}]\\n`);\n if (!simulated) {\n terminal.pause();\n getTermInfo(terminal,\n (remoteTermInfo) => {\n if (remoteTermInfo) {\n terminal.echo(`Remote platform info:`);\n terminal.echo(`OS: [[b;#fff;]${remoteTermInfo.platform}]`);\n if (remoteTermInfo.release) {\n terminal.echo(`OS release: [[b;#fff;]${remoteTermInfo.release}]`);\n }\n terminal.echo('\\r');\n } else {\n terminal.echo('[[;#f00;]Unable to get remote platform info.\\nDevice is not responding.]\\n');\n }\n terminal.resume();\n });\n }\n }\n}\n\nfunction currentPrompt(callback) {\n if (cwd) {\n callback('[[b;#2196f3;]' + deviceName +']: [[b;#8bc34a;]' + cwd +']> ');\n } else {\n callback('[[b;#8bc34a;]' + deviceName +']> ');\n }\n}\n\nfunction getTermInfo(terminal, callback) {\n self.ctx.controlApi.sendTwoWayCommand('getTermInfo', null, requestTimeout).then(\n (termInfo) => {\n cwd = termInfo.cwd;\n if (callback) {\n callback(termInfo);\n } \n },\n () => {\n if (callback) {\n callback(null);\n }\n }\n );\n}\n\nfunction sendCommand(terminal, command) {\n terminal.pause();\n var sendCommandRequest = {\n command: command,\n cwd: cwd\n };\n self.ctx.controlApi.sendTwoWayCommand('sendCommand', sendCommandRequest, requestTimeout).then(\n (responseBody) => {\n if (responseBody && responseBody.ok) {\n commandExecuting = true;\n setTimeout( pollCommandStatus.bind(null,terminal), commandStatusPollingInterval );\n } else {\n var error = responseBody ? responseBody.error : 'Unhandled error.';\n terminal.error(error);\n terminal.resume();\n }\n },\n () => {\n onRpcError(terminal);\n }\n );\n}\n\nfunction terminateCommand(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('terminateCommand', null, requestTimeout).then(\n (responseBody) => {\n if (!responseBody.ok) {\n commandExecuting = false;\n terminal.error(responseBody.error);\n terminal.resume();\n } \n },\n () => {\n onRpcError(terminal);\n }\n ); \n}\n\nfunction onRpcError(terminal) {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.resume();\n}\n\nfunction pollCommandStatus(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('getCommandStatus', null, requestTimeout).then(\n (commandStatusResponse) => {\n commandStatusResponse.data.forEach((dataElement) => {\n if (dataElement.stdout) {\n terminal.echo(dataElement.stdout);\n }\n if (dataElement.stderr) {\n terminal.error(dataElement.stderr);\n }\n }); \n if (commandStatusResponse.done) {\n commandExecuting = false;\n cwd = commandStatusResponse.cwd;\n terminal.resume();\n } else {\n var interval = commandStatusPollingInterval;\n if (!commandStatusResponse.data.length) {\n interval *=5;\n }\n setTimeout( pollCommandStatus.bind(null,terminal), interval );\n }\n },\n () => {\n commandExecuting = false;\n onRpcError(terminal);\n }\n );\n}\n\nself.onResize = function () {\n if (terminal) {\n terminal.resize(self.ctx.width, self.ctx.height);\n }\n}\n\nself.onDestroy = function() {\n}\n", | |
34 | + "controllerScript": "var requestTimeout = 500;\nvar commandStatusPollingInterval = 200;\n\nvar welcome = 'Welcome to ThingsBoard RPC remote shell.\\n';\n\nvar terminal, rpcEnabled, simulated, deviceName, cwd;\nvar commandExecuting = false;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n rpcEnabled = subscription.rpcEnabled;\n if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n deviceName = subscription.targetDeviceName;\n } else {\n deviceName = 'Simulated';\n simulated = true;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n \n terminal = $('#device-terminal', self.ctx.$container).terminal(\n function (command) {\n if (command && command.trim().length) {\n try {\n if (simulated) {\n this.echo(command);\n } else {\n sendCommand(this, command);\n }\n } catch(e) {\n this.error(e + '');\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: false,\n enabled: rpcEnabled,\n prompt: rpcEnabled ? currentPrompt : '',\n name: 'shell',\n pauseEvents: false,\n keydown: function (e, term) {\n if ((e.which == 67 || e.which == 68) && e.ctrlKey) { // CTRL+C || CTRL+D\n if (commandExecuting) {\n terminateCommand(term);\n return false;\n }\n }\n },\n onInit: initTerm\n }\n );\n \n};\n\nfunction initTerm(terminal) {\n terminal.echo(welcome);\n if (!rpcEnabled) {\n terminal.error('Target device is not set!\\n');\n } else {\n terminal.echo('Current target device for RPC terminal: [[b;#fff;]' + deviceName + ']\\n');\n if (!simulated) {\n terminal.pause();\n getTermInfo(terminal,\n function (remoteTermInfo) {\n if (remoteTermInfo) {\n terminal.echo('Remote platform info:');\n terminal.echo('OS: [[b;#fff;]' + remoteTermInfo.platform + ']');\n if (remoteTermInfo.release) {\n terminal.echo('OS release: [[b;#fff;]' + remoteTermInfo.release + ']');\n }\n terminal.echo('\\r');\n } else {\n terminal.echo('[[;#f00;]Unable to get remote platform info.\\nDevice is not responding.]\\n');\n }\n terminal.resume();\n });\n }\n }\n}\n\nfunction currentPrompt(callback) {\n if (cwd) {\n callback('[[b;#2196f3;]' + deviceName +']: [[b;#8bc34a;]' + cwd +']> ');\n } else {\n callback('[[b;#8bc34a;]' + deviceName +']> ');\n }\n}\n\nfunction getTermInfo(terminal, callback) {\n self.ctx.controlApi.sendTwoWayCommand('getTermInfo', null, requestTimeout).subscribe(\n function (termInfo) {\n cwd = termInfo.cwd;\n if (callback) {\n callback(termInfo);\n } \n },\n function () {\n if (callback) {\n callback(null);\n }\n }\n );\n}\n\nfunction sendCommand(terminal, command) {\n terminal.pause();\n var sendCommandRequest = {\n command: command,\n cwd: cwd\n };\n self.ctx.controlApi.sendTwoWayCommand('sendCommand', sendCommandRequest, requestTimeout).subscribe(\n function (responseBody) {\n if (responseBody && responseBody.ok) {\n commandExecuting = true;\n setTimeout( pollCommandStatus.bind(null,terminal), commandStatusPollingInterval );\n } else {\n var error = responseBody ? responseBody.error : 'Unhandled error.';\n terminal.error(error);\n terminal.resume();\n }\n },\n function () {\n onRpcError(terminal);\n }\n );\n}\n\nfunction terminateCommand(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('terminateCommand', null, requestTimeout).subscribe(\n function (responseBody) {\n if (!responseBody.ok) {\n commandExecuting = false;\n terminal.error(responseBody.error);\n terminal.resume();\n } \n },\n function () {\n onRpcError(terminal);\n }\n ); \n}\n\nfunction onRpcError(terminal) {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.resume();\n}\n\nfunction pollCommandStatus(terminal) {\n self.ctx.controlApi.sendTwoWayCommand('getCommandStatus', null, requestTimeout).subscribe(\n function (commandStatusResponse) {\n for (var i=0;i<commandStatusResponse.data.length;i++) {\n var dataElement = commandStatusResponse.data[i];\n if (dataElement.stdout) {\n terminal.echo(dataElement.stdout);\n }\n if (dataElement.stderr) {\n terminal.error(dataElement.stderr);\n }\n }\n if (commandStatusResponse.done) {\n commandExecuting = false;\n cwd = commandStatusResponse.cwd;\n terminal.resume();\n } else {\n var interval = commandStatusPollingInterval;\n if (!commandStatusResponse.data.length) {\n interval *=5;\n }\n setTimeout( pollCommandStatus.bind(null,terminal), interval );\n }\n },\n function () {\n commandExecuting = false;\n onRpcError(terminal);\n }\n );\n}\n\nself.onResize = function () {\n if (terminal) {\n terminal.resize(self.ctx.width, self.ctx.height);\n }\n};\n\nself.onDestroy = function() {\n};\n", | |
35 | 35 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"requestTimeout\"\n ]\n}", |
36 | 36 | "dataKeySettingsSchema": "{}\n", |
37 | 37 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#010101\",\"color\":\"rgba(255, 254, 254, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"RPC remote shell\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -45,9 +45,9 @@ |
45 | 45 | "sizeX": 5, |
46 | 46 | "sizeY": 4.5, |
47 | 47 | "resources": [], |
48 | - "templateHtml": "<tb-knob ctx='ctx'></tb-knob>", | |
48 | + "templateHtml": "<tb-knob [ctx]='ctx'></tb-knob>", | |
49 | 49 | "templateCss": "", |
50 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", | |
50 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", | |
51 | 51 | "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 \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"number\",\n \"default\": 50\n },\n \"title\": {\n \"title\": \"Knob title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"Set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"minValue\", \"maxValue\", \"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"minValue\",\n \"maxValue\",\n \"initialValue\",\n \"title\",\n \"getValueMethod\",\n \"setValueMethod\",\n \"requestTimeout\"\n ]\n}", |
52 | 52 | "dataKeySettingsSchema": "{}\n", |
53 | 53 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
... | ... | @@ -61,9 +61,9 @@ |
61 | 61 | "sizeX": 4, |
62 | 62 | "sizeY": 2.5, |
63 | 63 | "resources": [], |
64 | - "templateHtml": "<tb-switch ctx='ctx'></tb-switch>", | |
64 | + "templateHtml": "<tb-switch [ctx]='ctx'></tb-switch>", | |
65 | 65 | "templateCss": "", |
66 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", | |
66 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", | |
67 | 67 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", |
68 | 68 | "dataKeySettingsSchema": "{}\n", |
69 | 69 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
... | ... | @@ -77,9 +77,9 @@ |
77 | 77 | "sizeX": 2.5, |
78 | 78 | "sizeY": 2, |
79 | 79 | "resources": [], |
80 | - "templateHtml": "<tb-round-switch ctx='ctx'></tb-round-switch>", | |
80 | + "templateHtml": "<tb-round-switch [ctx]='ctx'></tb-round-switch>", | |
81 | 81 | "templateCss": "", |
82 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", | |
82 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", | |
83 | 83 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", |
84 | 84 | "dataKeySettingsSchema": "{}\n", |
85 | 85 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
... | ... | @@ -93,9 +93,9 @@ |
93 | 93 | "sizeX": 2.5, |
94 | 94 | "sizeY": 2.5, |
95 | 95 | "resources": [], |
96 | - "templateHtml": "<tb-led-indicator ctx='ctx'></tb-led-indicator>", | |
96 | + "templateHtml": "<tb-led-indicator [ctx]='ctx'></tb-led-indicator>", | |
97 | 97 | "templateCss": "", |
98 | - "controllerScript": "self.onInit = function() {\n var scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n if (self.ctx.resize) {\n self.ctx.resize();\n }\n}\n\nself.onDestroy = function() {\n}\n", | |
98 | + "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", | |
99 | 99 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", |
100 | 100 | "dataKeySettingsSchema": "{}\n", |
101 | 101 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" |
... | ... | @@ -109,9 +109,9 @@ |
109 | 109 | "sizeX": 4, |
110 | 110 | "sizeY": 2, |
111 | 111 | "resources": [], |
112 | - "templateHtml": "<div class=\"tb-rpc-button\" layout=\"column\">\n <div flex=\"20\" class=\"title-container\" layout=\"row\"\n layout-align=\"center center\" ng-show=\"showTitle\">\n <span class=\"button-title\">{{title}}</span>\n </div>\n <div flex=\"{{showTitle ? 80 : 100}}\" ng-style=\"{paddingTop: showTitle ? '5px': '10px'}\"\n class=\"button-container\" layout=\"column\" layout-align=\"center center\">\n <div>\n <md-button ng-click=\"sendCommand()\" ng-class=\"{'md-raised': styleButton.isRaised, 'md-primary': styleButton.isPrimary}\" ng-style=\"customStyle\">\n {{buttonLabel}}\n </md-button>\n </div>\n </div>\n <div class=\"error-container\" ng-style=\"{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n layout=\"row\" layout-align=\"center center\">\n <span class=\"button-error\">{{ error }}</span>\n </div>\n</div>", | |
113 | - "templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .md-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}", | |
114 | - "controllerScript": "self.onInit = function() {\n let rpcEnabled = self.ctx.defaultSubscription.rpcEnabled;\n\n self.ctx.$scope.buttonLabel = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton.bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n if (!rpcEnabled) {\n self.ctx.$scope.error =\n 'Target device is not set!';\n }\n\n self.ctx.$scope.sendCommand = function() {\n var rpcMethod = self.ctx.settings.methodName;\n var rpcParams = self.ctx.settings.methodParams;\n var timeout = self.ctx.settings.requestTimeout;\n var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ?\n true : false;\n\n var commandPromise;\n if (oneWayElseTwoWay) {\n commandPromise = self.ctx.controlApi.sendOneWayCommand(\n rpcMethod, rpcParams, timeout);\n } else {\n commandPromise = self.ctx.controlApi.sendTwoWayCommand(\n rpcMethod, rpcParams, timeout);\n }\n commandPromise.then(\n function success() {\n self.ctx.$scope.error = \"\";\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n }\n }\n );\n };\n\n};", | |
112 | + "templateHtml": "<div class=\"tb-rpc-button\" fxLayout=\"column\">\n <div fxFlex=\"20\" class=\"title-container\" fxLayout=\"row\"\n fxLayoutAlign=\"center center\" [fxShow]=\"showTitle\">\n <span class=\"button-title\">{{title}}</span>\n </div>\n <div fxFlex=\"{{showTitle ? 80 : 100}}\" [ngStyle]=\"{paddingTop: showTitle ? '5px': '10px'}\"\n class=\"button-container\" fxLayout=\"column\" fxLayoutAlign=\"center center\">\n <div>\n <button mat-button (click)=\"sendCommand()\"\n [class.mat-raised-button]=\"styleButton?.isRaised\"\n [color]=\"styleButton?.isPrimary ? 'primary' : ''\"\n [ngStyle]=\"customStyle\">\n {{buttonLable}}\n </button>\n </div>\n </div>\n <div class=\"error-container\" [ngStyle]=\"{'background': error?.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n fxLayout=\"row\" fxLayoutAlign=\"center center\">\n <span class=\"button-error\">{{ error }}</span>\n </div>\n</div>", | |
113 | + "templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .mat-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}", | |
114 | + "controllerScript": "self.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges();\n });\n};\n\nfunction init() {\n let rpcEnabled = self.ctx.defaultSubscription.rpcEnabled;\n\n self.ctx.$scope.buttonLable = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton.bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n if (!rpcEnabled) {\n self.ctx.$scope.error =\n 'Target device is not set!';\n }\n\n self.ctx.$scope.sendCommand = function() {\n var rpcMethod = self.ctx.settings.methodName;\n var rpcParams = self.ctx.settings.methodParams;\n var timeout = self.ctx.settings.requestTimeout;\n var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ?\n true : false;\n\n var commandPromise;\n if (oneWayElseTwoWay) {\n commandPromise = self.ctx.controlApi.sendOneWayCommand(\n rpcMethod, rpcParams, timeout);\n } else {\n commandPromise = self.ctx.controlApi.sendTwoWayCommand(\n rpcMethod, rpcParams, timeout);\n }\n commandPromise.subscribe(\n function success() {\n self.ctx.$scope.error = \"\";\n self.ctx.detectChanges();\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n self.ctx.detectChanges();\n }\n }\n );\n };\n}\n", | |
115 | 115 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"title\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"buttonText\": {\n \"title\": \"Button label\",\n \"type\": \"string\",\n \"default\": \"Send RPC\"\n },\n \"oneWayElseTwoWay\": {\n \"title\": \"Is One Way Command\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showError\": {\n \"title\": \"Show RPC command execution error\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"methodName\": {\n \"title\": \"RPC method\",\n \"type\": \"string\",\n \"default\": \"rpcCommand\"\n },\n \"methodParams\": {\n \"title\": \"RPC method params\",\n \"type\": \"string\",\n \"default\": \"{}\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 5000\n },\n \"styleButton\": {\n \"type\": \"object\",\n \"title\": \"Button Style\",\n \"properties\": {\n \"isRaised\": {\n \"type\": \"boolean\",\n \"title\": \"Raised\",\n \"default\": true\n },\n \"isPrimary\": {\n \"type\": \"boolean\",\n \"title\": \"Primary color\",\n \"default\": false\n },\n \"bgColor\": {\n \"type\": \"string\",\n \"title\": \"Button background color\",\n \"default\": null\n },\n \"textColor\": {\n \"type\": \"string\",\n \"title\": \"Button text color\",\n \"default\": null\n }\n }\n },\n \"required\": []\n }\n },\n \"form\": [\n \"title\",\n \"buttonText\",\n \"oneWayElseTwoWay\",\n \"showError\",\n \"methodName\",\n {\n \"key\": \"methodParams\",\n \"type\": \"json\"\n },\n \"requestTimeout\",\n {\n \"key\": \"styleButton\",\n \"items\": [\n \"styleButton.isRaised\",\n \"styleButton.isPrimary\",\n {\n \"key\": \"styleButton.bgColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"styleButton.textColor\",\n \"type\": \"color\"\n }\n ]\n }\n ]\n\n}", |
116 | 116 | "dataKeySettingsSchema": "{}\n", |
117 | 117 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":5000,\"oneWayElseTwoWay\":true,\"buttonText\":\"Send RPC\",\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"methodName\":\"rpcCommand\",\"methodParams\":\"{}\"},\"title\":\"RPC Button\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -125,13 +125,13 @@ |
125 | 125 | "sizeX": 4, |
126 | 126 | "sizeY": 2, |
127 | 127 | "resources": [], |
128 | - "templateHtml": "<div class=\"tb-rpc-button\" layout=\"column\">\n <div flex=\"20\" class=\"title-container\" layout=\"row\"\n layout-align=\"center center\" ng-show=\"showTitle\">\n <span class=\"button-title\">{{title}}</span>\n </div>\n <div flex=\"{{showTitle ? 80 : 100}}\" ng-style=\"{paddingTop: showTitle ? '5px': '10px'}\"\n class=\"button-container\" layout=\"column\" layout-align=\"center center\">\n <div>\n <md-button ng-click=\"sendUpdate()\" ng-class=\"{'md-raised': styleButton.isRaised, 'md-primary': styleButton.isPrimary}\" ng-style=\"customStyle\">\n {{buttonLabel}}\n </md-button>\n </div>\n </div>\n <div class=\"error-container\" ng-style=\"{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n layout=\"row\" layout-align=\"center center\">\n <span class=\"button-error\">{{ error }}</span>\n </div>\n</div>", | |
129 | - "templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .md-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}", | |
130 | - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.buttonLabel = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n let entityAttributeType = self.ctx.settings.entityAttributeType;\n let entityParameters = JSON.parse(self.ctx.settings.entityParameters);\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton\n .bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n console.log(self.ctx);\n\n let attributeService = self.ctx.$scope.$injector.get('attributeService');\n\n self.ctx.$scope.sendUpdate = function() {\n let attributes = [];\n for (let key in entityParameters) {\n attributes.push({\n \"key\": key,\n \"value\": entityParameters[key]\n });\n }\n \n \n attributeService.saveEntityAttributes(\"DEVICE\", self.ctx.defaultSubscription.targetDeviceId,\n entityAttributeType, attributes).then(\n function success() {\n self.ctx.$scope.error = \"\";\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n }\n console.log(rejection);\n }\n\n );\n };\n\n};", | |
128 | + "templateHtml": "<div class=\"tb-rpc-button\" fxLayout=\"column\">\n <div fxFlex=\"20\" class=\"title-container\" fxLayout=\"row\"\n fxLayoutAlign=\"center center\" [fxShow]=\"showTitle\">\n <span class=\"button-title\">{{title}}</span>\n </div>\n <div fxFlex=\"{{showTitle ? 80 : 100}}\" [ngStyle]=\"{paddingTop: showTitle ? '5px': '10px'}\"\n class=\"button-container\" fxLayout=\"column\" fxLayoutAlign=\"center center\">\n <div>\n <button mat-button (click)=\"sendUpdate()\"\n [class.mat-raised-button]=\"styleButton?.isRaised\"\n [color]=\"styleButton?.isPrimary ? 'primary' : ''\"\n [ngStyle]=\"customStyle\">\n {{buttonLable}}\n </button>\n </div>\n </div>\n <div class=\"error-container\" [ngStyle]=\"{'background': error?.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n fxLayout=\"row\" fxLayoutAlign=\"center center\">\n <span class=\"button-error\">{{ error }}</span>\n </div>\n</div>", | |
129 | + "templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .mat-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}", | |
130 | + "controllerScript": "self.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges();\n });\n};\n\nfunction init() {\n self.ctx.$scope.buttonLable = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n let entityAttributeType = self.ctx.settings.entityAttributeType;\n let entityParameters = JSON.parse(self.ctx.settings.entityParameters);\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton\n .bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n let attributeService = self.ctx.$scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n\n self.ctx.$scope.sendUpdate = function() {\n let attributes = [];\n for (let key in entityParameters) {\n attributes.push({\n \"key\": key,\n \"value\": entityParameters[key]\n });\n }\n \n let entityId = {\n entityType: \"DEVICE\",\n id: self.ctx.defaultSubscription.targetDeviceId\n };\n attributeService.saveEntityAttributes(entityId,\n entityAttributeType, attributes).subscribe(\n function success() {\n self.ctx.$scope.error = \"\";\n self.ctx.detectChanges();\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n self.ctx.detectChanges();\n }\n }\n\n );\n };\n}\n", | |
131 | 131 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"title\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"buttonText\": {\n \"title\": \"Button label\",\n \"type\": \"string\",\n \"default\": \"Update device attribute\"\n },\n \"entityAttributeType\": {\n \"title\": \"Device attribute scope\",\n \"type\": \"string\",\n \"default\": \"SERVER_SCOPE\"\n },\n \"entityParameters\": {\n \"title\": \"Device attribute parameters\",\n \"type\": \"string\",\n \"default\": \"{}\"\n },\n \"styleButton\": {\n \"type\": \"object\",\n \"title\": \"Button Style\",\n \"properties\": {\n \"isRaised\": {\n \"type\": \"boolean\",\n \"title\": \"Raised\",\n \"default\": true\n },\n \"isPrimary\": {\n \"type\": \"boolean\",\n \"title\": \"Primary color\",\n \"default\": false\n },\n \"bgColor\": {\n \"type\": \"string\",\n \"title\": \"Button background color\",\n \"default\": null\n },\n \"textColor\": {\n \"type\": \"string\",\n \"title\": \"Button text color\",\n \"default\": null\n }\n }\n },\n \"required\": []\n }\n },\n \"form\": [\n \"title\",\n \"buttonText\",\n {\n \"key\": \"entityAttributeType\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [{\n \"value\": \"SERVER_SCOPE\",\n \"label\": \"Server attribute\"\n }, {\n \"value\": \"SHARED_SCOPE\",\n \"label\": \"Shared attribute\"\n }]\n }, {\n \"key\": \"entityParameters\",\n \"type\": \"json\"\n },\n {\n \"key\": \"styleButton\",\n \"items\": [\n \"styleButton.isRaised\",\n \"styleButton.isPrimary\",\n {\n \"key\": \"styleButton.bgColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"styleButton.textColor\",\n \"type\": \"color\"\n }\n ]\n }\n ]\n\n}", |
132 | 132 | "dataKeySettingsSchema": "{}\n", |
133 | 133 | "defaultConfig": "{\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"entityParameters\":\"{}\",\"entityAttributeType\":\"SERVER_SCOPE\",\"buttonText\":\"Update device attribute\"},\"title\":\"Update device attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"targetDeviceAliases\":[]}" |
134 | 134 | } |
135 | 135 | } |
136 | 136 | ] |
137 | -} | |
\ No newline at end of file | ||
137 | +} | ... | ... |
... | ... | @@ -13,9 +13,9 @@ |
13 | 13 | "sizeX": 5, |
14 | 14 | "sizeY": 5.5, |
15 | 15 | "resources": [], |
16 | - "templateHtml": "<date-range-navigator-widget class=\"date-range-navigator-widget\" ctx=\"ctx\"></date-range-navigator-widget>", | |
16 | + "templateHtml": "<tb-date-range-navigator-widget [ctx]=\"ctx\"></tb-date-range-navigator-widget>", | |
17 | 17 | "templateCss": "", |
18 | - "controllerScript": "self.onInit = function() {\n scope = self.ctx.$scope;\n scope.ctx = self.ctx;\n}", | |
18 | + "controllerScript": "self.onInit = function() {\n}\n", | |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"hidePicker\": {\n \"title\": \"Hide date range picker\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"onePanel\": {\n \"title\": \"Date range picker one panel\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"autoConfirm\": {\n \"title\": \"Date range picker auto confirm\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"showTemplate\": {\n \"title\": \"Date range picker show template\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"firstDayOfWeek\": {\n \"title\": \"First day of the week\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"hideInterval\": {\n \"title\": \"Hide interval\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"initialInterval\": {\n\t\t\t\t\"title\": \"Initial interval\",\n\t\t\t\t\"type\": \"string\",\n\t\t\t\t\"default\": \"week\"\n\t\t\t},\n \"hideStepSize\": {\n \"title\": \"Hide step size\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"stepSize\": {\n\t\t\t\t\"title\": \"Initial step size\",\n\t\t\t\t\"type\": \"string\",\n\t\t\t\t\"default\": \"day\"\n\t\t\t},\n \"hideLabels\": {\n \"title\": \"Hide labels\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useSessionStorage\": {\n \"title\": \"Use session storage\",\n \"type\": \"boolean\",\n \"default\": true\n }\n }\n },\n \"form\": [\n \"hidePicker\",\n\t\t\"onePanel\",\n\t\t\"autoConfirm\",\n\t\t\"showTemplate\",\n\t\t\"firstDayOfWeek\",\n \"hideInterval\",\n {\n\t\t\t\"key\": \"initialInterval\",\n\t\t\t\"type\": \"rc-select\",\n\t\t\t\"multiple\": false,\n\t\t\t\"items\": [\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"hour\",\n\t\t\t\t\t\"label\": \"Hour\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"day\",\n\t\t\t\t\t\"label\": \"Day\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"week\",\n\t\t\t\t\t\"label\": \"Week\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"twoWeeks\",\n\t\t\t\t\t\"label\": \"2 weeks\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"month\",\n\t\t\t\t\t\"label\": \"Month\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"threeMonths\",\n\t\t\t\t\t\"label\": \"3 months\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"sixMonths\",\n\t\t\t\t\t\"label\": \"6 months\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n \"hideStepSize\",\n {\n\t\t\t\"key\": \"stepSize\",\n\t\t\t\"type\": \"rc-select\",\n\t\t\t\"multiple\": false,\n\t\t\t\"items\": [\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"hour\",\n\t\t\t\t\t\"label\": \"Hour\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"day\",\n\t\t\t\t\t\"label\": \"Day\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"week\",\n\t\t\t\t\t\"label\": \"Week\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"twoWeeks\",\n\t\t\t\t\t\"label\": \"2 weeks\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"month\",\n\t\t\t\t\t\"label\": \"Month\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"threeMonths\",\n\t\t\t\t\t\"label\": \"3 months\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"value\": \"sixMonths\",\n\t\t\t\t\t\"label\": \"6 months\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"hideLabels\",\n\t\t\"useSessionStorage\"\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{}\n", |
21 | 21 | "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\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"defaultInterval\":\"week\",\"stepSize\":\"day\"},\"title\":\"Date-range-navigator\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | ... | ... |
... | ... | @@ -13,9 +13,9 @@ |
13 | 13 | "sizeX": 4, |
14 | 14 | "sizeY": 2, |
15 | 15 | "resources": [], |
16 | - "templateHtml": "<fieldset class=\"gpio-panel\" ng-disabled=\"!rpcEnabled || executingRpcRequest\" style=\"height: 100%;\">\n <section class=\"gpio-row\" layout=\"row\" ng-repeat=\"row in rows track by $index\" \n ng-style=\"{'height': prefferedRowHeight+'px'}\">\n <section flex layout=\"row\" ng-repeat=\"cell in row track by $index\">\n <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n <section layout=\"row\" class=\"switch-panel\" layout-align=\"start center\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\">\n <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n <span flex ng-show=\"$index===1\"></span>\n <md-switch\n aria-label=\"{{ cell.label }}\"\n ng-disabled=\"!rpcEnabled || executingRpcRequest\"\n ng-model=\"cell.enabled\" \n ng-change=\"cell.enabled = !cell.enabled\" \n ng-click=\"gpioClick($event, cell)\">\n </md-switch>\n <span flex ng-show=\"$index===0\"></span>\n <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section layout=\"row\" flex ng-if=\"!cell\">\n <span flex ng-show=\"$index===0\"></span>\n <span class=\"switch-panel\"\n ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\"></span>\n <span flex ng-show=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" ng-show=\"rpcErrorText\">{{rpcErrorText}}</span>\n <md-progress-linear ng-show=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" md-mode=\"indeterminate\"></md-progress-linear> \n</fieldset>", | |
17 | - "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel md-switch {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel md-switch > div.md-container {\n margin: 0;\n}\n\n.switch-panel.col-0 md-switch {\n padding-left: 8px;\n padding-right: 4px;\n}\n\n.switch-panel.col-1 md-switch {\n padding-left: 4px;\n padding-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", | |
18 | - "controllerScript": "self.onInit = function() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .then(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .then(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n changeGpioStatus(gpio);\n };\n\n requestGpioStatus(); \n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n var switches = $('md-switch', self.ctx.$container);\n switches.css('height', 30*ratio+'px');\n switches.css('width', 36*ratio+'px');\n switches.css('min-width', 36*ratio+'px');\n $('.md-container', switches).css('height', 24*ratio+'px');\n $('.md-container', switches).css('width', 36*ratio+'px');\n var bars = $('.md-bar', self.ctx.$container);\n bars.css('height', 14*ratio+'px');\n bars.css('width', 34*ratio+'px');\n var thumbs = $('.md-thumb', self.ctx.$container);\n thumbs.css('height', 20*ratio+'px');\n thumbs.css('width', 20*ratio+'px');\n \n var leftLabels = $('.gpio-left-label', self.ctx.$container);\n leftLabels.css('font-size', 16*ratio+'px');\n var rightLabels = $('.gpio-right-label', self.ctx.$container);\n rightLabels.css('font-size', 16*ratio+'px');\n var pins = $('.pin', self.ctx.$container);\n var pinsFontSize = Math.max(9, 12*ratio);\n pins.css('font-size', pinsFontSize+'px'); \n}\n\nself.onDestroy = function() {\n}\n", | |
16 | + "templateHtml": "<fieldset class=\"gpio-panel\" style=\"height: 100%;\">\n <section class=\"gpio-row\" fxLayout=\"row\" *ngFor=\"let row of rows\" \n [ngStyle]=\"{'height': prefferedRowHeight+'px'}\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"switch-panel\" fxLayoutAlign=\"start center\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n <mat-slide-toggle\n [disabled]=\"!rpcEnabled || executingRpcRequest\"\n [checked]=\"cell.enabled\" \n (change)=\"gpioToggleChange($event, cell)\" \n (click)=\"gpioClick($event, cell)\">\n </mat-slide-toggle>\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"switch-panel\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" [fxShow]=\"rpcErrorText\">{{rpcErrorText}}</span>\n <mat-progress-bar [fxShow]=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" mode=\"indeterminate\"></mat-progress-bar>\n</fieldset>", | |
17 | + "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", | |
18 | + "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n self.ctx.detectChanges();\n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", | |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{}\n", |
21 | 21 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"Basic GPIO Control\"}" |
... | ... | @@ -29,9 +29,9 @@ |
29 | 29 | "sizeX": 5, |
30 | 30 | "sizeY": 2, |
31 | 31 | "resources": [], |
32 | - "templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n <section layout=\"row\" ng-repeat=\"row in rows\">\n <section flex layout=\"row\" ng-repeat=\"cell in row\">\n <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n <section layout=\"row\" class=\"led-panel\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n ng-style=\"{backgroundColor: ledPanelBackgroundColor }\">\n <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n <span class=\"led-container\">\n <tb-led-light size=\"prefferedRowHeight\"\n color-on=\"cell.colorOn\"\n color-off=\"cell.colorOff\"\n off-opacity=\"'0.9'\"\n tb-enabled=\"cell.enabled\">\n </tb-led-light>\n </span>\n <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section layout=\"row\" flex ng-if=\"!cell\">\n <span flex ng-show=\"$index===0\"></span>\n <span class=\"led-panel\"\n ng-style=\"{backgroundColor: ledPanelBackgroundColor }\"></span>\n <span flex ng-show=\"$index===1\"></span>\n </section>\n </section>\n </section> \n</div>", | |
32 | + "templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n <section fxLayout=\"row\" *ngFor=\"let row of rows\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"led-panel\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span class=\"led-container\">\n <tb-led-light [size]=\"prefferedRowHeight\"\n [colorOn]=\"cell.colorOn\"\n [colorOff]=\"cell.colorOff\"\n [offOpacity]=\"'0.9'\"\n [enabled]=\"cell.enabled\">\n </tb-led-light>\n </span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"led-panel\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n</div>", | |
33 | 33 | "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel tb-led-light > div {\n margin: auto;\n}\n\n.led-panel {\n margin: 0;\n width: 66px;\n min-width: 66px;\n}\n\n.led-container {\n width: 48px;\n min-width: 48px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.led-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.led-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", |
34 | - "controllerScript": "self.onInit = function() {\n var i, gpio;\n \n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n \n scope.gpioList = [];\n scope.gpioByPin = {};\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false,\n colorOn: tinycolor(gpio.color).lighten(20).toHexString(),\n colorOff: tinycolor(gpio.color).darken().toHexString()\n }\n );\n scope.gpioByPin[gpio.pin] = scope.gpioList[scope.gpioList.length-1];\n }\n\n scope.ledPanelBackgroundColor = settings.ledPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n var changed = false;\n for (var d = 0; d < self.ctx.data.length; d++) {\n var cellData = self.ctx.data[d];\n var dataKey = cellData.dataKey;\n var gpio = self.ctx.$scope.gpioByPin[dataKey.label];\n if (gpio) {\n var enabled = false;\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n enabled = (tvPair[1] === true || tvPair[1] === 'true');\n }\n if (gpio.enabled != enabled) {\n changed = true;\n gpio.enabled = enabled;\n }\n }\n }\n if (changed) {\n self.ctx.$scope.$digest();\n } \n}\n\nself.onResize = function() {\n var rowCount = self.ctx.$scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n self.ctx.$scope.prefferedRowHeight = prefferedRowHeight;\n \n var ratio = prefferedRowHeight/32;\n \n var leftLabels = $('.gpio-left-label', self.ctx.$container);\n leftLabels.css('font-size', 16*ratio+'px');\n var rightLabels = $('.gpio-right-label', self.ctx.$container);\n rightLabels.css('font-size', 16*ratio+'px');\n var pins = $('.pin', self.ctx.$container);\n var pinsFontSize = Math.max(9, 12*ratio);\n pins.css('font-size', pinsFontSize+'px'); \n}\n\nself.onDestroy = function() {\n}\n", | |
34 | + "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-panel-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n var i, gpio;\n \n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n \n scope.gpioList = [];\n scope.gpioByPin = {};\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false,\n colorOn: tinycolor(gpio.color).lighten(20).toHexString(),\n colorOff: tinycolor(gpio.color).darken().toHexString()\n }\n );\n scope.gpioByPin[gpio.pin] = scope.gpioList[scope.gpioList.length-1];\n }\n\n scope.ledPanelBackgroundColor = settings.ledPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n var changed = false;\n for (var d = 0; d < self.ctx.data.length; d++) {\n var cellData = self.ctx.data[d];\n var dataKey = cellData.dataKey;\n var gpio = self.ctx.$scope.gpioByPin[dataKey.label];\n if (gpio) {\n var enabled = false;\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n enabled = (tvPair[1] === true || tvPair[1] === 'true');\n }\n if (gpio.enabled != enabled) {\n changed = true;\n gpio.enabled = enabled;\n }\n }\n }\n if (changed) {\n self.ctx.detectChanges();\n } \n}\n\nself.onResize = function() {\n var rowCount = self.ctx.$scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n self.ctx.$scope.prefferedRowHeight = prefferedRowHeight;\n \n var ratio = prefferedRowHeight/32;\n \n var css = '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n \n cssParser.createStyleElement(namespace, css); \n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", | |
35 | 35 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio leds\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio led\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n },\n \"color\": {\n \"title\": \"Color\",\n \"type\": \"string\",\n \"default\": \"red\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\", \"color\"]\n }\n },\n \"ledPanelBackgroundColor\": {\n \"title\": \"LED panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n } \n },\n \"required\": [\"gpioList\", \n \"ledPanelBackgroundColor\"]\n },\n \"form\": [\n {\n \"key\": \"gpioList\",\n \"items\": [\n \"gpioList[].pin\",\n \"gpioList[].label\",\n \"gpioList[].row\",\n \"gpioList[].col\",\n {\n \"key\": \"gpioList[].color\",\n \"type\": \"color\"\n }\n ]\n },\n {\n \"key\": \"ledPanelBackgroundColor\",\n \"type\": \"color\"\n }\n ]\n}", |
36 | 36 | "dataKeySettingsSchema": "{}\n", |
37 | 37 | "defaultConfig": "{\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"color\":\"#008000\",\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"color\":\"#ffff00\",\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"color\":\"#cf006f\",\"_uniqueKey\":2}],\"ledPanelBackgroundColor\":\"#b71c1c\"},\"title\":\"Basic GPIO Panel\",\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"1\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.22518255793320163,\"funcBody\":\"var period = time % 1500;\\nreturn period < 500;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"2\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7008206860666621,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 500 && period < 1000;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"3\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.42600325102193426,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 1000;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}}}" |
... | ... | @@ -45,9 +45,9 @@ |
45 | 45 | "sizeX": 6, |
46 | 46 | "sizeY": 10.5, |
47 | 47 | "resources": [], |
48 | - "templateHtml": "<fieldset class=\"gpio-panel\" ng-disabled=\"!rpcEnabled || executingRpcRequest\" style=\"height: 100%;\">\n <section class=\"gpio-row\" layout=\"row\" ng-repeat=\"row in rows track by $index\" \n ng-style=\"{'height': prefferedRowHeight+'px'}\">\n <section flex layout=\"row\" ng-repeat=\"cell in row track by $index\">\n <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n <section layout=\"row\" class=\"switch-panel\" layout-align=\"start center\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\">\n <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n <span flex ng-show=\"$index===1\"></span>\n <md-switch\n aria-label=\"{{ cell.label }}\"\n ng-disabled=\"!rpcEnabled || executingRpcRequest\"\n ng-model=\"cell.enabled\" \n ng-change=\"cell.enabled = !cell.enabled\" \n ng-click=\"gpioClick($event, cell)\">\n </md-switch>\n <span flex ng-show=\"$index===0\"></span>\n <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section layout=\"row\" flex ng-if=\"!cell\">\n <span flex ng-show=\"$index===0\"></span>\n <span class=\"switch-panel\"\n ng-style=\"{'height': prefferedRowHeight+'px', 'backgroundColor': '{{ switchPanelBackgroundColor }}'}\"></span>\n <span flex ng-show=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" ng-show=\"rpcErrorText\">{{rpcErrorText}}</span>\n <md-progress-linear ng-show=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" md-mode=\"indeterminate\"></md-progress-linear> \n</fieldset>", | |
49 | - "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel md-switch {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel md-switch > div.md-container {\n margin: 0;\n}\n\n.switch-panel.col-0 md-switch {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 md-switch {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", | |
50 | - "controllerScript": "self.onInit = function() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .then(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .then(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n changeGpioStatus(gpio);\n };\n\n requestGpioStatus(); \n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n var switches = $('md-switch', self.ctx.$container);\n switches.css('height', 30*ratio+'px');\n switches.css('width', 36*ratio+'px');\n switches.css('min-width', 36*ratio+'px');\n $('.md-container', switches).css('height', 24*ratio+'px');\n $('.md-container', switches).css('width', 36*ratio+'px');\n var bars = $('.md-bar', self.ctx.$container);\n bars.css('height', 14*ratio+'px');\n bars.css('width', 34*ratio+'px');\n var thumbs = $('.md-thumb', self.ctx.$container);\n thumbs.css('height', 20*ratio+'px');\n thumbs.css('width', 20*ratio+'px');\n \n var leftLabels = $('.gpio-left-label', self.ctx.$container);\n leftLabels.css('font-size', 16*ratio+'px');\n var rightLabels = $('.gpio-right-label', self.ctx.$container);\n rightLabels.css('font-size', 16*ratio+'px');\n var pins = $('.pin', self.ctx.$container);\n var pinsFontSize = Math.max(9, 12*ratio);\n pins.css('font-size', pinsFontSize+'px'); \n}\n\nself.onDestroy = function() {\n}\n", | |
48 | + "templateHtml": "<fieldset class=\"gpio-panel\" style=\"height: 100%;\">\n <section class=\"gpio-row\" fxLayout=\"row\" *ngFor=\"let row of rows\" \n [ngStyle]=\"{'height': prefferedRowHeight+'px'}\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"switch-panel\" fxLayoutAlign=\"start center\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n <mat-slide-toggle\n [disabled]=\"!rpcEnabled || executingRpcRequest\"\n [checked]=\"cell.enabled\" \n (change)=\"gpioToggleChange($event, cell)\" \n (click)=\"gpioClick($event, cell)\">\n </mat-slide-toggle>\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"switch-panel\"\n [ngStyle]=\"{'height': prefferedRowHeight+'px', 'backgroundColor': switchPanelBackgroundColor }\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n <span class=\"error\" style=\"position: absolute; bottom: 5px;\" [fxShow]=\"rpcErrorText\">{{rpcErrorText}}</span>\n <mat-progress-bar [fxShow]=\"executingRpcRequest\" style=\"position: absolute; bottom: 0;\" mode=\"indeterminate\"></mat-progress-bar>\n</fieldset>", | |
49 | + "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.switch-panel {\n margin: 0;\n height: 32px;\n width: 66px;\n min-width: 66px;\n}\n\n.switch-panel mat-slide-toggle {\n margin: 0;\n width: 36px;\n min-width: 36px;\n}\n\n.switch-panel.col-0 mat-slide-toggle {\n margin-left: 8px;\n margin-right: 4px;\n}\n\n.switch-panel.col-1 mat-slide-toggle {\n margin-left: 4px;\n margin-right: 8px;\n}\n\n.gpio-row {\n height: 32px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", | |
50 | + "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-control-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n \n var i, gpio;\n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n scope.gpioList = [];\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false\n }\n );\n }\n\n scope.requestTimeout = settings.requestTimeout || 1000;\n\n scope.switchPanelBackgroundColor = settings.switchPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioStatusRequest = {\n method: \"getGpioStatus\",\n paramsBody: \"{}\"\n };\n \n if (settings.gpioStatusRequest) {\n scope.gpioStatusRequest.method = settings.gpioStatusRequest.method || scope.gpioStatusRequest.method;\n scope.gpioStatusRequest.paramsBody = settings.gpioStatusRequest.paramsBody || scope.gpioStatusRequest.paramsBody;\n }\n \n scope.gpioStatusChangeRequest = {\n method: \"setGpioStatus\",\n paramsBody: \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n };\n \n if (settings.gpioStatusChangeRequest) {\n scope.gpioStatusChangeRequest.method = settings.gpioStatusChangeRequest.method || scope.gpioStatusChangeRequest.method;\n scope.gpioStatusChangeRequest.paramsBody = settings.gpioStatusChangeRequest.paramsBody || scope.gpioStatusChangeRequest.paramsBody;\n }\n \n scope.parseGpioStatusFunction = \"return body[pin] === true;\";\n \n if (settings.parseGpioStatusFunction && settings.parseGpioStatusFunction.length > 0) {\n scope.parseGpioStatusFunction = settings.parseGpioStatusFunction;\n }\n \n scope.parseGpioStatusFunction = new Function(\"body, pin\", scope.parseGpioStatusFunction);\n \n function requestGpioStatus() {\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusRequest.method, \n scope.gpioStatusRequest.paramsBody, \n scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n for (var g = 0; g < scope.gpioList.length; g++) {\n var gpio = scope.gpioList[g];\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled; \n self.ctx.detectChanges();\n }\n }\n );\n }\n \n function changeGpioStatus(gpio) {\n var pin = gpio.pin + '';\n var enabled = !gpio.enabled;\n enabled = enabled === true ? 'true' : 'false';\n var paramsBody = scope.gpioStatusChangeRequest.paramsBody;\n var requestBody = JSON.parse(paramsBody.replace(\"\\\"{$pin}\\\"\", pin).replace(\"\\\"{$enabled}\\\"\", enabled));\n self.ctx.controlApi.sendTwoWayCommand(scope.gpioStatusChangeRequest.method, \n requestBody, scope.requestTimeout)\n .subscribe(\n function success(responseBody) {\n var enabled = scope.parseGpioStatusFunction.apply(this, [responseBody, gpio.pin]);\n gpio.enabled = enabled;\n self.ctx.detectChanges();\n }\n );\n }\n \n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n }\n\n scope.gpioClick = function($event, gpio) {\n if (scope.rpcEnabled && !scope.executingRpcRequest) {\n changeGpioStatus(gpio);\n }\n };\n \n scope.gpioToggleChange = function($event, gpio) {\n gpio.enabled = !$event.checked;\n $event.source.toggle();\n self.ctx.detectChanges();\n }\n \n if (scope.rpcEnabled) {\n requestGpioStatus(); \n }\n \n self.onResize();\n}\n\nself.onResize = function() {\n var scope = self.ctx.$scope;\n var rowCount = scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n scope.prefferedRowHeight = prefferedRowHeight;\n var ratio = prefferedRowHeight/32;\n \n var css = '.mat-slide-toggle .mat-slide-toggle-bar {\\n' +\n ' height: ' + 14*ratio+'px;\\n'+\n ' width: ' + 36*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb-container {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-thumb {\\n' +\n ' height: ' + 20*ratio+'px;\\n'+\n ' width: ' + 20*ratio+'px;\\n'+\n '}\\n';\n css += '.mat-slide-toggle .mat-slide-toggle-ripple {\\n' +\n ' height: ' + 40*ratio+'px;\\n'+\n ' width: ' + 40*ratio+'px;\\n'+\n ' top: calc(50% - '+20*ratio+'px);\\n'+\n ' left: calc(50% - '+20*ratio+'px);\\n'+\n '}\\n';\n css += '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n\n cssParser.createStyleElement(namespace, css);\n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", | |
51 | 51 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio switches\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio switch\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\"]\n }\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"switchPanelBackgroundColor\": {\n \"title\": \"Switches panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n },\n \"gpioStatusRequest\": {\n \"title\": \"GPIO status request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"getGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"gpioStatusChangeRequest\": {\n \"title\": \"GPIO status change request\",\n \"type\": \"object\",\n \"properties\": {\n \"method\": {\n \"title\": \"Method name\",\n \"type\": \"string\",\n \"default\": \"setGpioStatus\"\n },\n \"paramsBody\": {\n \"title\": \"Method body\",\n \"type\": \"string\",\n \"default\": \"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"\n }\n },\n \"required\": [\"method\", \"paramsBody\"]\n },\n \"parseGpioStatusFunction\": {\n \"title\": \"Parse gpio status function\",\n \"type\": \"string\",\n \"default\": \"return body[pin] === true;\"\n } \n },\n \"required\": [\"gpioList\", \n \"requestTimeout\",\n \"switchPanelBackgroundColor\",\n \"gpioStatusRequest\",\n \"gpioStatusChangeRequest\",\n \"parseGpioStatusFunction\"]\n },\n \"form\": [\n \"gpioList\",\n \"requestTimeout\",\n {\n \"key\": \"switchPanelBackgroundColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"gpioStatusRequest\",\n \"items\": [\n \"gpioStatusRequest.method\",\n {\n \"key\": \"gpioStatusRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"gpioStatusChangeRequest\",\n \"items\": [\n \"gpioStatusChangeRequest.method\",\n {\n \"key\": \"gpioStatusChangeRequest.paramsBody\",\n \"type\": \"json\"\n }\n ]\n },\n {\n \"key\": \"parseGpioStatusFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", |
52 | 52 | "dataKeySettingsSchema": "{}\n", |
53 | 53 | "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#008a00\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":7,\"label\":\"GPIO 4 (GPCLK0)\",\"row\":3,\"col\":0,\"_uniqueKey\":0},{\"pin\":11,\"label\":\"GPIO 17\",\"row\":5,\"col\":0,\"_uniqueKey\":1},{\"pin\":12,\"label\":\"GPIO 18\",\"row\":5,\"col\":1,\"_uniqueKey\":2},{\"_uniqueKey\":3,\"pin\":13,\"label\":\"GPIO 27\",\"row\":6,\"col\":0},{\"_uniqueKey\":4,\"pin\":15,\"label\":\"GPIO 22\",\"row\":7,\"col\":0},{\"_uniqueKey\":5,\"pin\":16,\"label\":\"GPIO 23\",\"row\":7,\"col\":1},{\"_uniqueKey\":6,\"pin\":18,\"label\":\"GPIO 24\",\"row\":8,\"col\":1},{\"_uniqueKey\":7,\"pin\":22,\"label\":\"GPIO 25\",\"row\":10,\"col\":1},{\"_uniqueKey\":8,\"pin\":29,\"label\":\"GPIO 5\",\"row\":14,\"col\":0},{\"_uniqueKey\":9,\"pin\":31,\"label\":\"GPIO 6\",\"row\":15,\"col\":0},{\"_uniqueKey\":10,\"pin\":32,\"label\":\"GPIO 12\",\"row\":15,\"col\":1},{\"_uniqueKey\":11,\"pin\":33,\"label\":\"GPIO 13\",\"row\":16,\"col\":0},{\"_uniqueKey\":12,\"pin\":35,\"label\":\"GPIO 19\",\"row\":17,\"col\":0},{\"_uniqueKey\":13,\"pin\":36,\"label\":\"GPIO 16\",\"row\":17,\"col\":1},{\"_uniqueKey\":14,\"pin\":37,\"label\":\"GPIO 26\",\"row\":18,\"col\":0},{\"_uniqueKey\":15,\"pin\":38,\"label\":\"GPIO 20\",\"row\":18,\"col\":1},{\"_uniqueKey\":16,\"pin\":40,\"label\":\"GPIO 21\",\"row\":19,\"col\":1}]},\"title\":\"Raspberry Pi GPIO Control\"}" |
... | ... | @@ -61,9 +61,9 @@ |
61 | 61 | "sizeX": 7, |
62 | 62 | "sizeY": 10.5, |
63 | 63 | "resources": [], |
64 | - "templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n <section layout=\"row\" ng-repeat=\"row in rows\">\n <section flex layout=\"row\" ng-repeat=\"cell in row\">\n <section layout=\"row\" flex ng-if=\"cell\" layout-align=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" ng-show=\"$index===0\">{{ cell.label }}</span>\n <section layout=\"row\" class=\"led-panel\" ng-class=\"$index===0 ? 'col-0' : 'col-1'\"\n ng-style=\"{backgroundColor: ledPanelBackgroundColor}\">\n <span class=\"pin\" ng-show=\"$index===0\">{{cell.pin}}</span>\n <span class=\"led-container\">\n <tb-led-light size=\"prefferedRowHeight\"\n color-on=\"cell.colorOn\"\n color-off=\"cell.colorOff\"\n off-opacity=\"'0.9'\"\n tb-enabled=\"cell.enabled\">\n </tb-led-light>\n </span>\n <span class=\"pin\" ng-show=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" ng-show=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section layout=\"row\" flex ng-if=\"!cell\">\n <span flex ng-show=\"$index===0\"></span>\n <span class=\"led-panel\"\n ng-style=\"{backgroundColor: ledPanelBackgroundColor}\"></span>\n <span flex ng-show=\"$index===1\"></span>\n </section>\n </section>\n </section> \n</div>", | |
64 | + "templateHtml": "<div class=\"gpio-panel\" style=\"height: 100%;\">\n <section fxLayout=\"row\" *ngFor=\"let row of rows\">\n <section fxFlex fxLayout=\"row\" *ngFor=\"let cell of row; let $index = index\">\n <section fxLayout=\"row\" fxFlex *ngIf=\"cell\" fxLayoutAlign=\"{{$index===0 ? 'end center' : 'start center'}}\">\n <span class=\"gpio-left-label\" [fxShow]=\"$index===0\">{{ cell.label }}</span>\n <section fxLayout=\"row\" class=\"led-panel\" [ngClass]=\"$index===0 ? 'col-0' : 'col-1'\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\">\n <span class=\"pin\" [fxShow]=\"$index===0\">{{cell.pin}}</span>\n <span class=\"led-container\">\n <tb-led-light [size]=\"prefferedRowHeight\"\n [colorOn]=\"cell.colorOn\"\n [colorOff]=\"cell.colorOff\"\n [offOpacity]=\"'0.9'\"\n [enabled]=\"cell.enabled\">\n </tb-led-light>\n </span>\n <span class=\"pin\" [fxShow]=\"$index===1\">{{cell.pin}}</span>\n </section>\n <span class=\"gpio-right-label\" [fxShow]=\"$index===1\">{{ cell.label }}</span>\n </section>\n <section fxLayout=\"row\" fxFlex *ngIf=\"!cell\">\n <span fxFlex [fxShow]=\"$index===0\"></span>\n <span class=\"led-panel\"\n [ngStyle]=\"{backgroundColor: ledPanelBackgroundColor}\"></span>\n <span fxFlex [fxShow]=\"$index===1\"></span>\n </section>\n </section>\n </section> \n</div>", | |
65 | 65 | "templateCss": ".error {\n font-size: 14px !important;\n color: maroon;/*rgb(250,250,250);*/\n background-color: transparent;\n padding: 6px;\n}\n\n.error span {\n margin: auto;\n}\n\n.gpio-panel {\n padding-top: 10px;\n white-space: nowrap;\n}\n\n.gpio-panel tb-led-light > div {\n margin: auto;\n}\n\n.led-panel {\n margin: 0;\n width: 66px;\n min-width: 66px;\n}\n\n.led-container {\n width: 48px;\n min-width: 48px;\n}\n\n.pin {\n margin-top: auto;\n margin-bottom: auto;\n color: white;\n font-size: 12px;\n width: 16px;\n min-width: 16px;\n}\n\n.led-panel.col-0 .pin {\n margin-left: auto;\n padding-left: 2px;\n text-align: right;\n}\n\n.led-panel.col-1 .pin {\n margin-right: auto;\n \n text-align: left;\n}\n\n.gpio-left-label {\n margin-right: 8px;\n}\n\n.gpio-right-label {\n margin-left: 8px;\n}", |
66 | - "controllerScript": "self.onInit = function() {\n var i, gpio;\n \n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n \n scope.gpioList = [];\n scope.gpioByPin = {};\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false,\n colorOn: tinycolor(gpio.color).lighten(20).toHexString(),\n colorOff: tinycolor(gpio.color).darken().toHexString()\n }\n );\n scope.gpioByPin[gpio.pin] = scope.gpioList[scope.gpioList.length-1];\n }\n\n scope.ledPanelBackgroundColor = settings.ledPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n var changed = false;\n for (var d = 0; d < self.ctx.data.length; d++) {\n var cellData = self.ctx.data[d];\n var dataKey = cellData.dataKey;\n var gpio = self.ctx.$scope.gpioByPin[dataKey.label];\n if (gpio) {\n var enabled = false;\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n enabled = (tvPair[1] === true || tvPair[1] === 'true');\n }\n if (gpio.enabled != enabled) {\n changed = true;\n gpio.enabled = enabled;\n }\n }\n }\n if (changed) {\n self.ctx.$scope.$digest();\n } \n}\n\nself.onResize = function() {\n var rowCount = self.ctx.$scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n self.ctx.$scope.prefferedRowHeight = prefferedRowHeight;\n \n var ratio = prefferedRowHeight/32;\n \n var leftLabels = $('.gpio-left-label', self.ctx.$container);\n leftLabels.css('font-size', 16*ratio+'px');\n var rightLabels = $('.gpio-right-label', self.ctx.$container);\n rightLabels.css('font-size', 16*ratio+'px');\n var pins = $('.pin', self.ctx.$container);\n var pinsFontSize = Math.max(9, 12*ratio);\n pins.css('font-size', pinsFontSize+'px'); \n}\n\nself.onDestroy = function() {\n}\n", | |
66 | + "controllerScript": "var namespace;\nvar cssParser = new cssjs();\n\nself.onInit = function() {\n var utils = self.ctx.$injector.get(self.ctx.servicesMap.get('utils'));\n namespace = 'gpio-panel-' + utils.guid();\n cssParser.testMode = false;\n cssParser.cssPreviewNamespace = namespace;\n self.ctx.$container.addClass(namespace);\n self.ctx.ngZone.run(function() {\n init(); \n });\n}\n\nfunction init() {\n var i, gpio;\n \n var scope = self.ctx.$scope;\n var settings = self.ctx.settings;\n \n scope.gpioList = [];\n scope.gpioByPin = {};\n for (var g = 0; g < settings.gpioList.length; g++) {\n gpio = settings.gpioList[g];\n scope.gpioList.push(\n {\n row: gpio.row,\n col: gpio.col,\n pin: gpio.pin,\n label: gpio.label,\n enabled: false,\n colorOn: tinycolor(gpio.color).lighten(20).toHexString(),\n colorOff: tinycolor(gpio.color).darken().toHexString()\n }\n );\n scope.gpioByPin[gpio.pin] = scope.gpioList[scope.gpioList.length-1];\n }\n\n scope.ledPanelBackgroundColor = settings.ledPanelBackgroundColor || tinycolor('green').lighten(2).toRgbString();\n\n scope.gpioCells = {};\n var rowCount = 0;\n for (i = 0; i < scope.gpioList.length; i++) {\n gpio = scope.gpioList[i];\n scope.gpioCells[gpio.row+'_'+gpio.col] = gpio;\n rowCount = Math.max(rowCount, gpio.row+1);\n }\n \n scope.prefferedRowHeight = 32;\n scope.rows = [];\n for (i = 0; i < rowCount; i++) {\n var row = [];\n for (var c =0; c<2;c++) {\n if (scope.gpioCells[i+'_'+c]) {\n row[c] = scope.gpioCells[i+'_'+c];\n } else {\n row[c] = null;\n }\n }\n scope.rows.push(row);\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n var changed = false;\n for (var d = 0; d < self.ctx.data.length; d++) {\n var cellData = self.ctx.data[d];\n var dataKey = cellData.dataKey;\n var gpio = self.ctx.$scope.gpioByPin[dataKey.label];\n if (gpio) {\n var enabled = false;\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length - 1];\n enabled = (tvPair[1] === true || tvPair[1] === 'true');\n }\n if (gpio.enabled != enabled) {\n changed = true;\n gpio.enabled = enabled;\n }\n }\n }\n if (changed) {\n self.ctx.detectChanges();\n } \n}\n\nself.onResize = function() {\n var rowCount = self.ctx.$scope.rows.length;\n var prefferedRowHeight = (self.ctx.height - 35)/rowCount;\n prefferedRowHeight = Math.min(32, prefferedRowHeight);\n prefferedRowHeight = Math.max(12, prefferedRowHeight);\n self.ctx.$scope.prefferedRowHeight = prefferedRowHeight;\n \n var ratio = prefferedRowHeight/32;\n \n var css = '.gpio-left-label, .gpio-right-label {\\n' +\n ' font-size: ' + 16*ratio+'px;\\n'+\n '}\\n';\n var pinsFontSize = Math.max(9, 12*ratio);\n css += '.pin {\\n' +\n ' font-size: ' + pinsFontSize+'px;\\n'+\n '}\\n';\n \n cssParser.createStyleElement(namespace, css); \n \n self.ctx.detectChanges();\n}\n\nself.onDestroy = function() {\n}\n", | |
67 | 67 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"gpioList\": {\n \"title\": \"Gpio leds\",\n \"type\": \"array\",\n \"minItems\" : 1,\n \"items\": {\n \"title\": \"Gpio led\",\n \"type\": \"object\",\n \"properties\": {\n \"pin\": {\n \"title\": \"Pin\",\n \"type\": \"number\"\n },\n \"label\": {\n \"title\": \"Label\",\n \"type\": \"string\"\n },\n \"row\": {\n \"title\": \"Row\",\n \"type\": \"number\"\n },\n \"col\": {\n \"title\": \"Column\",\n \"type\": \"number\"\n },\n \"color\": {\n \"title\": \"Color\",\n \"type\": \"string\",\n \"default\": \"red\"\n }\n },\n \"required\": [\"pin\", \"label\", \"row\", \"col\", \"color\"]\n }\n },\n \"ledPanelBackgroundColor\": {\n \"title\": \"LED panel background color\",\n \"type\": \"string\",\n \"default\": \"#008a00\"\n } \n },\n \"required\": [\"gpioList\", \n \"ledPanelBackgroundColor\"]\n },\n \"form\": [\n {\n \"key\": \"gpioList\",\n \"items\": [\n \"gpioList[].pin\",\n \"gpioList[].label\",\n \"gpioList[].row\",\n \"gpioList[].col\",\n {\n \"key\": \"gpioList[].color\",\n \"type\": \"color\"\n }\n ]\n },\n {\n \"key\": \"ledPanelBackgroundColor\",\n \"type\": \"color\"\n }\n ]\n}", |
68 | 68 | "dataKeySettingsSchema": "{}\n", |
69 | 69 | "defaultConfig": "{\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"gpioList\":[{\"pin\":1,\"label\":\"3.3V\",\"row\":0,\"col\":0,\"color\":\"#fc9700\",\"_uniqueKey\":0},{\"pin\":2,\"label\":\"5V\",\"row\":0,\"col\":1,\"color\":\"#fb0000\",\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 2 (I2C1_SDA)\",\"row\":1,\"col\":0,\"color\":\"#02fefb\",\"_uniqueKey\":2},{\"color\":\"#fb0000\",\"pin\":4,\"label\":\"5V\",\"row\":1,\"col\":1},{\"color\":\"#02fefb\",\"pin\":5,\"label\":\"GPIO 3 (I2C1_SCL)\",\"row\":2,\"col\":0},{\"color\":\"#000000\",\"pin\":6,\"label\":\"GND\",\"row\":2,\"col\":1},{\"color\":\"#00fd00\",\"pin\":7,\"label\":\"GPIO 4 (GPCLK0)\",\"row\":3,\"col\":0},{\"color\":\"#fdfb00\",\"pin\":8,\"label\":\"GPIO 14 (UART_TXD)\",\"row\":3,\"col\":1},{\"color\":\"#000000\",\"pin\":9,\"label\":\"GND\",\"row\":4,\"col\":0},{\"color\":\"#fdfb00\",\"pin\":10,\"label\":\"GPIO 15 (UART_RXD)\",\"row\":4,\"col\":1},{\"color\":\"#00fd00\",\"pin\":11,\"label\":\"GPIO 17\",\"row\":5,\"col\":0},{\"color\":\"#00fd00\",\"pin\":12,\"label\":\"GPIO 18\",\"row\":5,\"col\":1},{\"color\":\"#00fd00\",\"pin\":13,\"label\":\"GPIO 27\",\"row\":6,\"col\":0},{\"color\":\"#000000\",\"pin\":14,\"label\":\"GND\",\"row\":6,\"col\":1},{\"color\":\"#00fd00\",\"pin\":15,\"label\":\"GPIO 22\",\"row\":7,\"col\":0},{\"color\":\"#00fd00\",\"pin\":16,\"label\":\"GPIO 23\",\"row\":7,\"col\":1},{\"color\":\"#fc9700\",\"pin\":17,\"label\":\"3.3V\",\"row\":8,\"col\":0},{\"color\":\"#00fd00\",\"pin\":18,\"label\":\"GPIO 24\",\"row\":8,\"col\":1},{\"color\":\"#fd01fd\",\"pin\":19,\"label\":\"GPIO 10 (SPI_MOSI)\",\"row\":9,\"col\":0},{\"color\":\"#000000\",\"pin\":20,\"label\":\"GND\",\"row\":9,\"col\":1},{\"color\":\"#fd01fd\",\"pin\":21,\"label\":\"GPIO 9 (SPI_MISO)\",\"row\":10,\"col\":0},{\"color\":\"#00fd00\",\"pin\":22,\"label\":\"GPIO 25\",\"row\":10,\"col\":1},{\"color\":\"#fd01fd\",\"pin\":23,\"label\":\"GPIO 11 (SPI_SCLK)\",\"row\":11,\"col\":0},{\"color\":\"#fd01fd\",\"pin\":24,\"label\":\"GPIO 8 (SPI_CE0)\",\"row\":11,\"col\":1},{\"color\":\"#000000\",\"pin\":25,\"label\":\"GND\",\"row\":12,\"col\":0},{\"color\":\"#fd01fd\",\"pin\":26,\"label\":\"GPIO 7 (SPI_CE1)\",\"row\":12,\"col\":1},{\"color\":\"#ffffff\",\"pin\":27,\"label\":\"ID_SD\",\"row\":13,\"col\":0},{\"color\":\"#ffffff\",\"pin\":28,\"label\":\"ID_SC\",\"row\":13,\"col\":1},{\"color\":\"#00fd00\",\"pin\":29,\"label\":\"GPIO 5\",\"row\":14,\"col\":0},{\"color\":\"#000000\",\"pin\":30,\"label\":\"GND\",\"row\":14,\"col\":1},{\"color\":\"#00fd00\",\"pin\":31,\"label\":\"GPIO 6\",\"row\":15,\"col\":0},{\"color\":\"#00fd00\",\"pin\":32,\"label\":\"GPIO 12\",\"row\":15,\"col\":1},{\"color\":\"#00fd00\",\"pin\":33,\"label\":\"GPIO 13\",\"row\":16,\"col\":0},{\"color\":\"#000000\",\"pin\":34,\"label\":\"GND\",\"row\":16,\"col\":1},{\"color\":\"#00fd00\",\"pin\":35,\"label\":\"GPIO 19\",\"row\":17,\"col\":0},{\"color\":\"#00fd00\",\"pin\":36,\"label\":\"GPIO 16\",\"row\":17,\"col\":1},{\"color\":\"#00fd00\",\"pin\":37,\"label\":\"GPIO 26\",\"row\":18,\"col\":0},{\"color\":\"#00fd00\",\"pin\":38,\"label\":\"GPIO 20\",\"row\":18,\"col\":1},{\"color\":\"#000000\",\"pin\":39,\"label\":\"GND\",\"row\":19,\"col\":0},{\"color\":\"#00fd00\",\"pin\":40,\"label\":\"GPIO 21\",\"row\":19,\"col\":1}],\"ledPanelBackgroundColor\":\"#008a00\"},\"title\":\"Raspberry Pi GPIO Panel\",\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"7\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.22518255793320163,\"funcBody\":\"var period = time % 1500;\\nreturn period < 500;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"11\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7008206860666621,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 500 && period < 1000;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"12\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.42600325102193426,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 1000;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"13\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.48362241571415243,\"funcBody\":\"var period = time % 1500;\\nreturn period < 500;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"29\",\"color\":\"#607d8b\",\"settings\":{},\"_hash\":0.7217670147518815,\"funcBody\":\"var period = time % 1500;\\nreturn period >= 500 && period < 1000;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}}}" | ... | ... |
... | ... | @@ -11,11 +11,11 @@ |
11 | 11 | "descriptor": { |
12 | 12 | "type": "latest", |
13 | 13 | "sizeX": 7.5, |
14 | - "sizeY": 3.5, | |
14 | + "sizeY": 3, | |
15 | 15 | "resources": [], |
16 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n maxlength=\"{{settings.maxLength}}\"\n minlength=\"{{settings.minLength}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-attribute' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-attribute' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
17 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
18 | - "controllerScript": "let $scope;\r\nlet settings;\r\nlet attributeService;\r\nlet toast;\r\nlet utils;\r\nlet types;\r\nlet $translate;\r\n\r\nself.onInit = function() {\r\n\r\n $scope = self.ctx.$scope;\r\n attributeService = $scope.$injector.get('attributeService');\r\n toast = $scope.$injector.get('toast');\r\n utils = $scope.$injector.get('utils');\r\n types = $scope.$injector.get('types');\r\n $translate = $scope.$injector.get('$translate');\r\n settings = self.ctx.settings || {};\r\n $scope.settings = settings;\r\n $scope.isValidParameter = true;\r\n $scope.dataKeyDetected = false;\r\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-attribute-required');\r\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\r\n\r\n if (self.ctx.datasources && self.ctx.datasources.length) {\r\n var datasource = self.ctx.datasources[0];\r\n if (datasource.type === types.datasourceType.entity) {\r\n if (datasource.entityType && datasource.entityId) {\r\n $scope.entityName = datasource.entityName;\r\n if (settings.widgetTitle && settings.widgetTitle.length) {\r\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\r\n } else {\r\n $scope.titleTemplate = self.ctx.widgetConfig.title;\r\n }\r\n\r\n $scope.entityDetected = true;\r\n }\r\n }\r\n if (datasource.dataKeys.length) {\r\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\r\n $scope.isValidParameter = false;\r\n } else {\r\n $scope.currentKey = datasource.dataKeys[0].name;\r\n $scope.dataKeyType = datasource.dataKeys[0].type;\r\n $scope.dataKeyDetected = true;\r\n }\r\n }\r\n }\r\n\r\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\r\n\r\n $scope.updateAttribute = function () {\r\n if ($scope.entityDetected) {\r\n var datasource = self.ctx.datasources[0];\r\n\r\n attributeService.saveEntityAttributes(\r\n datasource.entityType,\r\n datasource.entityId,\r\n types.attributesScope.server.value,\r\n [\r\n {\r\n key: $scope.currentKey,\r\n value: $scope.currentValue\r\n }\r\n ]\r\n ).then(\r\n function success() {\r\n $scope.originalValue = $scope.currentValue;\r\n if (settings.showResultMessage) {\r\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\r\n }\r\n },\r\n function fail() {\r\n if (settings.showResultMessage) {\r\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\r\n }\r\n }\r\n );\r\n }\r\n };\r\n\r\n $scope.changeFocus = function () {\r\n if ($scope.currentValue === $scope.originalValue) {\r\n $scope.isFocused = false;\r\n }\r\n }\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n\r\n try {\r\n if ($scope.dataKeyDetected) {\r\n if (!$scope.isFocused) {\r\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\r\n $scope.$digest();\r\n }\r\n }\r\n } catch (e) {\r\n console.log(e);\r\n }\r\n}\r\n\r\nself.onResize = function() {\r\n\r\n}\r\n\r\nself.typeParameters = function() {\r\n return {\r\n maxDatasources: 1,\r\n maxDataKeys: 1\r\n }\r\n}\r\n\r\nself.onDestroy = function() {\r\n\r\n}\r\n", | |
16 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n maxlength=\"{{settings.maxLength}}\"\n minlength=\"{{settings.minLength}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
17 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
18 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false; \n\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.minLength(settings.minLength),\n $scope.validators.maxLength(settings.maxLength)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SERVER_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue($scope.originalValue);\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
19 | 19 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxLength\": {\n \"title\": \"Max length\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minLength\": {\n \"title\": \"Min length\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxLength\",\n \"minLength\"\n ]\n}", |
20 | 20 | "dataKeySettingsSchema": "{}\n", |
21 | 21 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"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\":{},\"title\":\"Update server string attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -29,9 +29,9 @@ |
29 | 29 | "sizeX": 7.5, |
30 | 30 | "sizeY": 3, |
31 | 31 | "resources": [], |
32 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n type=\"number\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-attribute' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-attribute' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
33 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
34 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-attribute-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.server.value,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.currentValue === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\n correctValue($scope.currentValue);\n $scope.$digest();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n $scope.currentValue = 0;\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
32 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n type=\"number\"\n step=\"1\"\n pattern=\"^-?[0-9]+$\"\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\" >\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
33 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
34 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false; \n\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.min(settings.minValue),\n $scope.validators.max(settings.maxValue),\n $scope.validators.pattern(/^-?[0-9]+$/)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n \n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SERVER_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue(correctValue($scope.originalValue));\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n return 0;\n }\n return value;\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
35 | 35 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValue\": {\n \"title\": \"Max value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minValue\": {\n \"title\": \"Min value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxValue\",\n \"minValue\"\n ]\n}", |
36 | 36 | "dataKeySettingsSchema": "{}\n", |
37 | 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\":\"Update server integer attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -45,9 +45,9 @@ |
45 | 45 | "sizeX": 7.5, |
46 | 46 | "sizeY": 3, |
47 | 47 | "resources": [], |
48 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n type=\"number\"\n step=\"any\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-attribute' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-attribute' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
49 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
50 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-attribute-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\n \n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.server.value,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.currentValue === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\n correctValue($scope.currentValue);\n $scope.$digest();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n $scope.currentValue = 0;\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
48 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n type=\"number\"\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\" >\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
49 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
50 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false; \n\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.min(settings.minValue),\n $scope.validators.max(settings.maxValue)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SERVER_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue(correctValue($scope.originalValue));\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n return 0;\n }\n return value;\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
51 | 51 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValue\": {\n \"title\": \"Max value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minValue\": {\n \"title\": \"Min value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxValue\",\n \"minValue\"\n ]\n}", |
52 | 52 | "dataKeySettingsSchema": "{}\n", |
53 | 53 | "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\":\"Update server double attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -61,9 +61,9 @@ |
61 | 61 | "sizeX": 7.5, |
62 | 62 | "sizeY": 3, |
63 | 63 | "resources": [], |
64 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-checkbox ng-model=\"checkboxValue\"\n aria-label=\"{{ 'widgets.input-widgets.switch-attribute-value' | translate }}\"\n ng-change=\"changed()\"\n ng-true-value=\"'true'\"\n ng-false-value=\"'false'\"\n >\n {{currentValue}}\n </md-checkbox>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
65 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
66 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n\n settings.trueValue = utils.customTranslation(settings.trueValue, settings.trueValue) || true;\n settings.falseValue = utils.customTranslation(settings.falseValue, settings.falseValue) || false;\n\n map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n mapReverse = {[settings.trueValue]:true, [settings.falseValue]:false};\n $scope.checkboxValue = \"false\";\n $scope.currentValue = map[$scope.checkboxValue];\n\n $scope.changed = function () {\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.updateAttribute();\n }\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.server.value,\n [\n {\n key: $scope.currentKey,\n value: mapReverse[$scope.currentValue] || false\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n}\n\nself.onDataUpdated = function() {\n try {\n if ($scope.dataKeyDetected) {\n $scope.checkboxValue = ($scope.originalValue = self.ctx.data[0].data[0][1]) || false;\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.$digest();\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onResize = function() {}\nself.onDestroy = function() {}\n", | |
64 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\r\n <form *ngIf=\"attributeUpdateFormGroup\"\r\n class=\"attribute-update-form\"\r\n [formGroup]=\"attributeUpdateFormGroup\"\r\n (ngSubmit)=\"updateAttribute()\">\r\n <div style=\"padding: 0 8px; margin: auto 0;\">\r\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\r\n <div class=\"grid__element\">\r\n <mat-checkbox formControlName=\"checkboxValue\"\r\n (change)=\"changed()\"\r\n aria-label=\"{{'widgets.input-widgets.switch-timeseries-value' | translate}}\">\r\n {{currentValue}}\r\n </mat-checkbox>\r\n </div>\r\n </div>\r\n\r\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\">\r\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\r\n </div>\r\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\r\n [fxShow]=\"entityDetected && !dataKeyDetected\">\r\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\r\n </div>\r\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\r\n [fxShow]=\"entityDetected && !isValidParameter\">\r\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\r\n </div>\r\n </div>\r\n </form>\r\n</div>", | |
65 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
66 | + "controllerScript": "let settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\nlet $scope;\nlet map;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init();\n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n\n settings.trueValue = utils.defaultValue(utils.customTranslation(settings.trueValue, settings.trueValue), true);\n settings.falseValue = utils.defaultValue(utils.customTranslation(settings.falseValue, settings.falseValue), false);\n\n map = {\n true: settings.trueValue,\n false: settings.falseValue\n };\n \n $scope.checkboxValue = false;\n $scope.currentValue = map[$scope.checkboxValue];\n\n $scope.attributeUpdateFormGroup = $scope.fb.group({checkboxValue: [$scope.checkboxValue]});\n\n $scope.changed = function() {\n $scope.checkboxValue = $scope.attributeUpdateFormGroup.get('checkboxValue').value;\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.updateAttribute();\n };\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function() {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SERVER_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.checkboxValue\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('checkboxValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n}\n\nself.onDataUpdated = function() {\n try {\n $scope.checkboxValue = self.ctx.data[0].data[0][1] === 'true';\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.attributeUpdateFormGroup.get('checkboxValue').patchValue($scope.checkboxValue);\n self.ctx.detectChanges();\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {}", | |
67 | 67 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"trueValue\": {\n \"title\": \"True value\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"falseValue\": {\n \"title\": \"False value\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"trueValue\",\n \"falseValue\"\n ]\n}", |
68 | 68 | "dataKeySettingsSchema": "{}\n", |
69 | 69 | "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\":\"Update server boolean attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -123,11 +123,11 @@ |
123 | 123 | "descriptor": { |
124 | 124 | "type": "latest", |
125 | 125 | "sizeX": 7.5, |
126 | - "sizeY": 3.5, | |
126 | + "sizeY": 3, | |
127 | 127 | "resources": [], |
128 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n maxlength=\"{{settings.maxLength}}\"\n minlength=\"{{settings.minLength}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-attribute' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-attribute' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n ng-hide=\"entityDetected\"\n ng-bind=\"message\"\n ></div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
129 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
130 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.message = $translate.instant('widgets.input-widgets.no-entity-selected');\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-attribute-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType === types.entityType.device) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n } else {\n $scope.message = $translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.shared.value,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.currentValue === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.$digest();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
128 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n maxlength=\"{{settings.maxLength}}\"\n minlength=\"{{settings.minLength}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\" [innerHtml]=\"message\"></div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
129 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
130 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false; \n $scope.message = translate.instant('widgets.input-widgets.no-entity-selected');\n \n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.minLength(settings.minLength),\n $scope.validators.maxLength(settings.maxLength)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType === 'DEVICE') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n \n $scope.entityDetected = true;\n }\n } else {\n $scope.message = translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SHARED_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue($scope.originalValue);\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
131 | 131 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxLength\": {\n \"title\": \"Max length\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minLength\": {\n \"title\": \"Min length\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxLength\",\n \"minLength\"\n ]\n}", |
132 | 132 | "dataKeySettingsSchema": "{}\n", |
133 | 133 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.23592248334107624,\"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\":{},\"title\":\"Update shared string attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -141,9 +141,9 @@ |
141 | 141 | "sizeX": 7.5, |
142 | 142 | "sizeY": 3, |
143 | 143 | "resources": [], |
144 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n type=\"number\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-attribute' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-attribute' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n ng-hide=\"entityDetected\"\n ng-bind=\"message\"\n >\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
145 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
146 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-attribute-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\n $scope.message = $translate.instant('widgets.input-widgets.no-entity-selected');\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType === types.entityType.device) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n } else {\n $scope.message = $translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.shared.value,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.currentValue === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\n correctValue($scope.currentValue);\n $scope.$digest();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n $scope.currentValue = 0;\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
144 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n type=\"number\"\n step=\"1\"\n pattern=\"^-?[0-9]+$\"\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\" [innerHtml]=\"message\"></div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
145 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
146 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false; \n $scope.message = translate.instant('widgets.input-widgets.no-entity-selected');\n \n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.min(settings.minValue),\n $scope.validators.max(settings.maxValue),\n $scope.validators.pattern(/^-?[0-9]+$/)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType === 'DEVICE') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n \n $scope.entityDetected = true;\n }\n } else {\n $scope.message = translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SHARED_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue(correctValue($scope.originalValue));\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n return 0;\n }\n return value;\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
147 | 147 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValue\": {\n \"title\": \"Max value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minValue\": {\n \"title\": \"Min value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxValue\",\n \"minValue\"\n ]\n}", |
148 | 148 | "dataKeySettingsSchema": "{}\n", |
149 | 149 | "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\":\"Update shared integer attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -157,9 +157,9 @@ |
157 | 157 | "sizeX": 7.5, |
158 | 158 | "sizeY": 3, |
159 | 159 | "resources": [], |
160 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n type=\"number\"\n step=\"any\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-attribute' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-attribute' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\" ng-bind=\"message\"></div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
161 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
162 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-attribute-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\n $scope.message = $translate.instant('widgets.input-widgets.no-entity-selected');\n \n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType === types.entityType.device) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n } else {\n $scope.message = $translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.shared.value,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.currentValue === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\n correctValue($scope.currentValue);\n $scope.$digest();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n $scope.currentValue = 0;\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
160 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n type=\"number\"\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\" [innerHtml]=\"message\"></div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
161 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
162 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false; \n $scope.message = translate.instant('widgets.input-widgets.no-entity-selected');\n \n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.min(settings.minValue),\n $scope.validators.max(settings.maxValue)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType === 'DEVICE') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n \n $scope.entityDetected = true;\n }\n } else {\n $scope.message = translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SHARED_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n ).subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue(correctValue($scope.originalValue));\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n return 0;\n }\n return value;\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
163 | 163 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValue\": {\n \"title\": \"Max value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minValue\": {\n \"title\": \"Min value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxValue\",\n \"minValue\"\n ]\n}", |
164 | 164 | "dataKeySettingsSchema": "{}\n", |
165 | 165 | "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\":\"Update shared double attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -173,12 +173,12 @@ |
173 | 173 | "sizeX": 7.5, |
174 | 174 | "sizeY": 3, |
175 | 175 | "resources": [], |
176 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-checkbox ng-model=\"checkboxValue\"\n aria-label=\"{{ 'widgets.input-widgets.switch-attribute-value' | translate }}\"\n ng-change=\"changed()\"\n ng-true-value=\"'true'\"\n ng-false-value=\"'false'\"\n >\n {{currentValue}}\n </md-checkbox>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\" ng-bind=\"message\"></div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
177 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
178 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.message = $translate.instant('widgets.input-widgets.no-entity-selected');\n\n settings.trueValue = utils.customTranslation(settings.trueValue, settings.trueValue) || true;\n settings.falseValue = utils.customTranslation(settings.falseValue, settings.falseValue) || false;\n\n map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n mapReverse = {[settings.trueValue]:true, [settings.falseValue]:false};\n $scope.checkboxValue = \"false\";\n $scope.currentValue = map[$scope.checkboxValue];\n\n $scope.changed = function () {\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.updateAttribute();\n }\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType === types.entityType.device) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n } else {\n $scope.message = $translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.attribute) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n attributeService.saveEntityAttributes(\n datasource.entityType,\n datasource.entityId,\n types.attributesScope.shared.value,\n [\n {\n key: $scope.currentKey,\n value: mapReverse[$scope.currentValue] || false\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n}\n\nself.onDataUpdated = function() {\n try {\n $scope.checkboxValue = ($scope.originalValue = self.ctx.data[0].data[0][1]) || 'false';\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.$digest();\n\n } catch (e) {\n console.log(e);\n }\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onResize = function() {}\nself.onDestroy = function() {}\n", | |
176 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\r\n <form *ngIf=\"attributeUpdateFormGroup\"\r\n class=\"attribute-update-form\"\r\n [formGroup]=\"attributeUpdateFormGroup\"\r\n (ngSubmit)=\"updateAttribute()\">\r\n <div style=\"padding: 0 8px; margin: auto 0;\">\r\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\r\n <div class=\"grid__element\">\r\n <mat-checkbox formControlName=\"checkboxValue\"\r\n (change)=\"changed()\"\r\n aria-label=\"{{'widgets.input-widgets.switch-timeseries-value' | translate}}\">\r\n {{currentValue}}\r\n </mat-checkbox>\r\n </div>\r\n </div>\r\n\r\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\" [innerHtml]=\"message\"></div>\r\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\r\n [fxShow]=\"entityDetected && !dataKeyDetected\">\r\n {{ 'widgets.input-widgets.no-attribute-selected' | translate }}\r\n </div>\r\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\r\n [fxShow]=\"entityDetected && !isValidParameter\">\r\n {{ 'widgets.input-widgets.timeseries-not-allowed' | translate }}\r\n </div>\r\n </div>\r\n </form>\r\n</div>", | |
177 | + "templateCss": ".attribute-update-form {\r\n overflow: hidden;\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.attribute-update-form__grid {\r\n display: flex;\r\n}\r\n.grid__element:first-child {\r\n flex: 1;\r\n}\r\n\r\n.grid__element {\r\n display: flex;\r\n}\r\n\r\n.attribute-update-form .mat-button.mat-icon-button {\r\n margin: 0;\r\n}\r\n\r\n.attribute-update-form .mat-button.mat-icon-button {\r\n width: 32px;\r\n min-width: 32px;\r\n height: 32px;\r\n min-height: 32px;\r\n padding: 0 !important;\r\n margin: 0 !important;\r\n line-height: 20px;\r\n}\r\n\r\n.attribute-update-form .mat-icon-button mat-icon {\r\n width: 20px;\r\n min-width: 20px;\r\n height: 20px;\r\n min-height: 20px;\r\n font-size: 20px;\r\n}\r\n\r\n.tb-toast {\r\n font-size: 14px!important;\r\n}", | |
178 | + "controllerScript": "let settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\nlet $scope;\nlet map;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init();\n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.message = translate.instant('widgets.input-widgets.no-entity-selected');\n\n settings.trueValue = utils.defaultValue(utils.customTranslation(settings.trueValue, settings.trueValue), true);\n settings.falseValue = utils.defaultValue(utils.customTranslation(settings.falseValue, settings.falseValue), false);\n\n map = {\n true: settings.trueValue,\n false: settings.falseValue\n };\n \n $scope.checkboxValue = false;\n $scope.currentValue = map[$scope.checkboxValue];\n\n $scope.attributeUpdateFormGroup = $scope.fb.group({checkboxValue: [$scope.checkboxValue]});\n\n $scope.changed = function() {\n $scope.checkboxValue = $scope.attributeUpdateFormGroup.get('checkboxValue').value;\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.updateAttribute();\n };\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType === 'DEVICE') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n \n $scope.entityDetected = true;\n }\n } else {\n $scope.message = translate.instant('widgets.input-widgets.not-allowed-entity');\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"attribute\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function() {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n attributeService.saveEntityAttributes(\n datasource.entity.id,\n 'SHARED_SCOPE',\n [\n {\n key: $scope.currentKey,\n value: $scope.checkboxValue || false\n }\n ]\n ).subscribe(\n function success() {\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n };\n}\n\nself.onDataUpdated = function() {\n try {\n $scope.checkboxValue = self.ctx.data[0].data[0][1] === 'true';\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.attributeUpdateFormGroup.get('checkboxValue').patchValue($scope.checkboxValue);\n self.ctx.detectChanges();\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {}", | |
179 | 179 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"trueValue\": {\n \"title\": \"True value\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"falseValue\": {\n \"title\": \"False value\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"trueValue\",\n \"falseValue\"\n ]\n}", |
180 | 180 | "dataKeySettingsSchema": "{}\n", |
181 | - "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\":{\"trueValue\":\"active\",\"falseValue\":\"inactive\"},\"title\":\"Update shared boolean attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | |
181 | + "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\":\"Update shared boolean attribute\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | |
182 | 182 | } |
183 | 183 | }, |
184 | 184 | { |
... | ... | @@ -237,9 +237,9 @@ |
237 | 237 | "sizeX": 7.5, |
238 | 238 | "sizeY": 3, |
239 | 239 | "resources": [], |
240 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n maxlength=\"{{settings.maxLength}}\"\n minlength=\"{{settings.minLength}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-timeseries' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
241 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
242 | - "controllerScript": "let $scope;\r\nlet settings;\r\nlet attributeService;\r\nlet toast;\r\nlet utils;\r\nlet types;\r\nlet $translate;\r\nlet $q\r\nlet $http;\r\n\r\nself.onInit = function() {\r\n\r\n $scope = self.ctx.$scope;\r\n attributeService = $scope.$injector.get('attributeService');\r\n toast = $scope.$injector.get('toast');\r\n utils = $scope.$injector.get('utils');\r\n types = $scope.$injector.get('types');\r\n $translate = $scope.$injector.get('$translate');\r\n $q = $scope.$injector.get('$q');\r\n $http = $scope.$injector.get('$http');\r\n settings = self.ctx.settings || {};\r\n $scope.settings = settings;\r\n $scope.isValidParameter = true;\r\n $scope.dataKeyDetected = false;\r\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-timeseries-required');\r\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\r\n\r\n if (self.ctx.datasources && self.ctx.datasources.length) {\r\n var datasource = self.ctx.datasources[0];\r\n if (datasource.type === types.datasourceType.entity) {\r\n if (datasource.entityType && datasource.entityId) {\r\n $scope.entityName = datasource.entityName;\r\n if (settings.widgetTitle && settings.widgetTitle.length) {\r\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\r\n } else {\r\n $scope.titleTemplate = self.ctx.widgetConfig.title;\r\n }\r\n\r\n $scope.entityDetected = true;\r\n }\r\n }\r\n if (datasource.dataKeys.length) {\r\n if (datasource.dataKeys[0].type != types.dataKeyType.timeseries) {\r\n $scope.isValidParameter = false;\r\n } else {\r\n $scope.currentKey = datasource.dataKeys[0].name;\r\n $scope.dataKeyType = datasource.dataKeys[0].type;\r\n $scope.dataKeyDetected = true;\r\n }\r\n }\r\n }\r\n\r\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\r\n\r\n $scope.updateAttribute = function () {\r\n if ($scope.entityDetected) {\r\n var datasource = self.ctx.datasources[0];\r\n\r\n saveEntityTimeseries(\r\n datasource.entityType,\r\n datasource.entityId,\r\n [\r\n {\r\n key: $scope.currentKey,\r\n value: $scope.currentValue\r\n }\r\n ]\r\n ).then(\r\n function success() {\r\n $scope.originalValue = $scope.currentValue;\r\n if (settings.showResultMessage) {\r\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\r\n }\r\n },\r\n function fail() {\r\n if (settings.showResultMessage) {\r\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\r\n }\r\n }\r\n );\r\n }\r\n };\r\n\r\n $scope.changeFocus = function () {\r\n if ($scope.currentValue === $scope.originalValue) {\r\n $scope.isFocused = false;\r\n }\r\n }\r\n\r\n function saveEntityTimeseries(entityType, entityId, telemetries) {\r\n var deferred = $q.defer();\r\n var telemetriesData = {};\r\n for (var a = 0; a < telemetries.length; a++) {\r\n if (angular.isDefined(telemetries[a].value) && telemetries[a].value !== null) {\r\n telemetriesData[telemetries[a].key] = telemetries[a].value;\r\n }\r\n }\r\n if (Object.keys(telemetriesData).length) {\r\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\r\n $http.post(url, telemetriesData).then(\r\n function(response) {\r\n deferred.resolve(response.data);\r\n },\r\n function() {\r\n deferred.reject();\r\n }\r\n );\r\n }\r\n return deferred.promise;\r\n }\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n try {\r\n if ($scope.dataKeyDetected) {\r\n if (!$scope.isFocused) {\r\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\r\n $scope.$digest();\r\n }\r\n }\r\n } catch (e) {\r\n console.log(e);\r\n }\r\n}\r\n\r\nself.onResize = function() {\r\n\r\n}\r\n\r\nself.typeParameters = function() {\r\n return {\r\n maxDatasources: 1,\r\n maxDataKeys: 1\r\n }\r\n}\r\n\r\nself.onDestroy = function() {\r\n\r\n}\r\n", | |
240 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n maxlength=\"{{settings.maxLength}}\"\n minlength=\"{{settings.minLength}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
241 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
242 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.minLength(settings.minLength),\n $scope.validators.maxLength(settings.maxLength)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"timeseries\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n let observable = saveEntityTimeseries(\n datasource.entityType,\n datasource.entityId,\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n );\n if (observable) {\n observable.subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n\n function saveEntityTimeseries(entityType, entityId, telemetries) {\n var telemetriesData = {};\n for (var a = 0; a < telemetries.length; a++) {\n if (typeof telemetries[a].value !== 'undefined' && telemetries[a].value !== null) {\n telemetriesData[telemetries[a].key] = telemetries[a].value;\n }\n }\n if (Object.keys(telemetriesData).length) {\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\n return http.post(url, telemetriesData);\n }\n return null;\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue($scope.originalValue);\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
243 | 243 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxLength\": {\n \"title\": \"Max length\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minLength\": {\n \"title\": \"Min length\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxLength\",\n \"minLength\"\n ]\n}", |
244 | 244 | "dataKeySettingsSchema": "{}\n", |
245 | 245 | "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\":\"Update string timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -253,12 +253,12 @@ |
253 | 253 | "sizeX": 7.5, |
254 | 254 | "sizeY": 3, |
255 | 255 | "resources": [], |
256 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-checkbox ng-model=\"checkboxValue\"\n aria-label=\"{{ 'widgets.input-widgets.switch-timeseries-value' | translate }}\"\n ng-change=\"changed()\"\n ng-true-value=\"'true'\"\n ng-false-value=\"'false'\"\n >\n {{currentValue}}\n </md-checkbox>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
257 | - "templateCss": ".attribute-update-form {\r\n overflow: hidden;\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.entity-title {\r\n font-weight: bold;\r\n font-size: 22px;\r\n padding-top: 12px;\r\n padding-bottom: 6px;\r\n color: #666;\r\n}\r\n\r\n.attribute-update-form__grid {\r\n display: flex;\r\n}\r\n.grid__element:first-child {\r\n flex: 1;\r\n}\r\n\r\n.grid__element {\r\n display: flex;\r\n}\r\n\r\n.attribute-update-form .md-button.md-icon-button {\r\n margin: 0;\r\n}\r\n\r\n.attribute-update-form .md-button.md-icon-button {\r\n width: 32px;\r\n min-width: 32px;\r\n height: 32px;\r\n min-height: 32px;\r\n padding: 0 !important;\r\n margin: 0 !important;\r\n line-height: 20px;\r\n}\r\n\r\n.attribute-update-form .md-icon-button md-icon {\r\n width: 20px;\r\n min-width: 20px;\r\n height: 20px;\r\n min-height: 20px;\r\n font-size: 20px;\r\n}\r\n\r\n\r\nmd-toast{\r\n min-width: 0;\r\n}\r\nmd-toast .md-toast-content {\r\n font-size: 14px!important;\r\n}", | |
258 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\nlet $q\nlet $http;\nlet map;\nlet mapReverse;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n $q = $scope.$injector.get('$q');\n $http = $scope.$injector.get('$http');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n\n settings.trueValue = utils.customTranslation(settings.trueValue, settings.trueValue) || true;\n settings.falseValue = utils.customTranslation(settings.falseValue, settings.falseValue) || false;\n \n map = {\"true\":settings.trueValue, \"false\": settings.falseValue};\n mapReverse = {[settings.trueValue]:\"true\", [settings.falseValue]:\"false\"};\n $scope.checkboxValue = \"false\";\n $scope.currentValue = map[$scope.checkboxValue];\n\n $scope.changed = function () {\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.updateAttribute();\n }\n \n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.timeseries) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n saveEntityTimeseries(\n datasource.entityType,\n datasource.entityId,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n function saveEntityTimeseries(entityType, entityId, telemetries) {\n var deferred = $q.defer();\n var telemetriesData = {};\n for (var a = 0; a < telemetries.length; a++) {\n if (angular.isDefined(telemetries[a].value) && telemetries[a].value !== null) {\n telemetriesData[telemetries[a].key] = telemetries[a].value;\n }\n }\n if (Object.keys(telemetriesData).length) {\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\n $http.post(url, telemetriesData).then(\n function(response) {\n deferred.resolve(response.data);\n },\n function() {\n deferred.reject();\n }\n );\n }\n return deferred.promise;\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n $scope.checkboxValue = mapReverse[$scope.originalValue = self.ctx.data[0].data[0][1]] || 'false';\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.$digest();\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
256 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-checkbox formControlName=\"checkboxValue\"\n (change)=\"changed()\"\n aria-label=\"{{'widgets.input-widgets.switch-timeseries-value' | translate}}\">\n {{currentValue}}\n </mat-checkbox>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\"\n [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
257 | + "templateCss": ".attribute-update-form {\r\n overflow: hidden;\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.attribute-update-form__grid {\r\n display: flex;\r\n}\r\n.grid__element:first-child {\r\n flex: 1;\r\n}\r\n\r\n.grid__element {\r\n display: flex;\r\n}\r\n\r\n.attribute-update-form .mat-button.mat-icon-button {\r\n margin: 0;\r\n}\r\n\r\n.attribute-update-form .mat-button.mat-icon-button {\r\n width: 32px;\r\n min-width: 32px;\r\n height: 32px;\r\n min-height: 32px;\r\n padding: 0 !important;\r\n margin: 0 !important;\r\n line-height: 20px;\r\n}\r\n\r\n.attribute-update-form .mat-icon-button mat-icon {\r\n width: 20px;\r\n min-width: 20px;\r\n height: 20px;\r\n min-height: 20px;\r\n font-size: 20px;\r\n}\r\n\r\n.tb-toast {\r\n font-size: 14px!important;\r\n}", | |
258 | + "controllerScript": "let settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\nlet $scope;\nlet map;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init();\n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n\n settings.trueValue = utils.defaultValue(utils.customTranslation(settings.trueValue, settings.trueValue), true);\n settings.falseValue = utils.defaultValue(utils.customTranslation(settings.falseValue, settings.falseValue), false);\n\n map = {\n true: settings.trueValue,\n false: settings.falseValue\n };\n \n $scope.checkboxValue = false;\n $scope.currentValue = map[$scope.checkboxValue];\n\n $scope.attributeUpdateFormGroup = $scope.fb.group({checkboxValue: [$scope.checkboxValue]});\n\n $scope.changed = function() {\n $scope.checkboxValue = $scope.attributeUpdateFormGroup.get('checkboxValue').value;\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.updateAttribute();\n };\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"timeseries\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function() {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n let observable = saveEntityTimeseries(\n datasource.entityType,\n datasource.entityId,\n [{\n key: $scope.currentKey,\n value: $scope.checkboxValue\n }]\n );\n\n if (observable) {\n observable.subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('checkboxValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n }\n };\n\n function saveEntityTimeseries(entityType, entityId, telemetries) {\n var telemetriesData = {};\n for (var a = 0; a < telemetries.length; a++) {\n if (typeof telemetries[a].value !== 'undefined' && telemetries[a].value !== null) {\n telemetriesData[telemetries[a].key] = telemetries[a].value;\n }\n }\n if (Object.keys(telemetriesData).length) {\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\n return http.post(url, telemetriesData);\n }\n return null;\n }\n}\n\nself.onDataUpdated = function() {\n try {\n $scope.checkboxValue = self.ctx.data[0].data[0][1] === 'true';\n $scope.currentValue = map[$scope.checkboxValue];\n $scope.attributeUpdateFormGroup.get('checkboxValue').patchValue($scope.checkboxValue);\n self.ctx.detectChanges();\n } catch (e) {\n console.log(e);\n }\n}\n\nself.onResize = function() {}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {}", | |
259 | 259 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"trueValue\": {\n \"title\": \"True value\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"falseValue\": {\n \"title\": \"False value\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"trueValue\",\n \"falseValue\"\n ]\n}", |
260 | 260 | "dataKeySettingsSchema": "{}\n", |
261 | - "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\":{\"trueValue\":\"active\",\"falseValue\":\"inactive\"},\"title\":\"Update boolean timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | |
261 | + "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\":\"Update boolean timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | |
262 | 262 | } |
263 | 263 | }, |
264 | 264 | { |
... | ... | @@ -269,9 +269,9 @@ |
269 | 269 | "sizeX": 7.5, |
270 | 270 | "sizeY": 3, |
271 | 271 | "resources": [], |
272 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n type=\"number\"\n step=\"any\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-timeseries' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
273 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
274 | - "controllerScript": "let $scope;\r\nlet settings;\r\nlet attributeService;\r\nlet toast;\r\nlet utils;\r\nlet types;\r\nlet $translate;\r\nlet $q;\r\nlet $http;\r\n\r\nself.onInit = function() {\r\n\r\n $scope = self.ctx.$scope;\r\n attributeService = $scope.$injector.get('attributeService');\r\n toast = $scope.$injector.get('toast');\r\n utils = $scope.$injector.get('utils');\r\n types = $scope.$injector.get('types');\r\n $translate = $scope.$injector.get('$translate');\r\n $q = $scope.$injector.get('$q');\r\n $http = $scope.$injector.get('$http');\r\n settings = angular.copy(self.ctx.settings) || {};\r\n $scope.settings = settings;\r\n $scope.isValidParameter = true;\r\n $scope.dataKeyDetected = false;\r\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-timeseries-required');\r\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\r\n\r\n if (self.ctx.datasources && self.ctx.datasources.length) {\r\n var datasource = self.ctx.datasources[0];\r\n if (datasource.type === types.datasourceType.entity) {\r\n if (datasource.entityType && datasource.entityId) {\r\n $scope.entityName = datasource.entityName;\r\n if (settings.widgetTitle && settings.widgetTitle.length) {\r\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\r\n } else {\r\n $scope.titleTemplate = self.ctx.widgetConfig.title;\r\n }\r\n\r\n $scope.entityDetected = true;\r\n }\r\n }\r\n if (datasource.dataKeys.length) {\r\n if (datasource.dataKeys[0].type != types.dataKeyType.timeseries) {\r\n $scope.isValidParameter = false;\r\n } else {\r\n $scope.currentKey = datasource.dataKeys[0].name;\r\n $scope.dataKeyType = datasource.dataKeys[0].type;\r\n $scope.dataKeyDetected = true;\r\n }\r\n }\r\n }\r\n\r\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\r\n\r\n $scope.updateAttribute = function () {\r\n if ($scope.entityDetected) {\r\n var datasource = self.ctx.datasources[0];\r\n\r\n saveEntityTimeseries(\r\n datasource.entityType,\r\n datasource.entityId,\r\n [\r\n {\r\n key: $scope.currentKey,\r\n value: $scope.currentValue\r\n }\r\n ]\r\n ).then(\r\n function success() {\r\n $scope.originalValue = $scope.currentValue;\r\n if (settings.showResultMessage) {\r\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\r\n }\r\n },\r\n function fail() {\r\n if (settings.showResultMessage) {\r\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\r\n }\r\n }\r\n );\r\n }\r\n };\r\n\r\n $scope.changeFocus = function () {\r\n if ($scope.currentValue === $scope.originalValue) {\r\n $scope.isFocused = false;\r\n }\r\n }\r\n\r\n function saveEntityTimeseries(entityType, entityId, telemetries) {\r\n var deferred = $q.defer();\r\n var telemetriesData = {};\r\n for (var a = 0; a < telemetries.length; a++) {\r\n if (angular.isDefined(telemetries[a].value) && telemetries[a].value !== null) {\r\n telemetriesData[telemetries[a].key] = telemetries[a].value;\r\n }\r\n }\r\n if (Object.keys(telemetriesData).length) {\r\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\r\n $http.post(url, telemetriesData).then(\r\n function(response) {\r\n deferred.resolve(response.data);\r\n },\r\n function() {\r\n deferred.reject();\r\n }\r\n );\r\n }\r\n return deferred.promise;\r\n }\r\n}\r\n\r\nself.onDataUpdated = function() {\r\n\r\n try {\r\n if ($scope.dataKeyDetected) {\r\n if (!$scope.isFocused) {\r\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\r\n correctValue($scope.currentValue);\r\n $scope.$digest();\r\n }\r\n }\r\n } catch (e) {\r\n console.log(e);\r\n }\r\n}\r\n\r\nfunction correctValue(value) {\r\n if (typeof value !== \"number\") {\r\n $scope.currentValue = 0;\r\n }\r\n}\r\n\r\nself.onResize = function() {\r\n\r\n}\r\n\r\nself.typeParameters = function() {\r\n return {\r\n maxDatasources: 1,\r\n maxDataKeys: 1\r\n }\r\n}\r\n\r\nself.onDestroy = function() {\r\n\r\n}\r\n", | |
272 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n <form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n type=\"number\"\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n \n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n \n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n </form>\n</div>", | |
273 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}", | |
274 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.min(settings.minValue),\n $scope.validators.max(settings.maxValue)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"timeseries\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n let observable = saveEntityTimeseries(\n datasource.entityType,\n datasource.entityId,\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n );\n if (observable) {\n observable.subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n\n function saveEntityTimeseries(entityType, entityId, telemetries) {\n var telemetriesData = {};\n for (var a = 0; a < telemetries.length; a++) {\n if (typeof telemetries[a].value !== 'undefined' && telemetries[a].value !== null) {\n telemetriesData[telemetries[a].key] = telemetries[a].value;\n }\n }\n if (Object.keys(telemetriesData).length) {\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\n return http.post(url, telemetriesData);\n }\n return null;\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue(correctValue($scope.originalValue));\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n return 0;\n }\n return value;\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n dataKeyOptional: true\n }\n}\n\nself.onDestroy = function() {\n\n}", | |
275 | 275 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValue\": {\n \"title\": \"Max value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minValue\": {\n \"title\": \"Min value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxValue\",\n \"minValue\"\n ]\n}", |
276 | 276 | "dataKeySettingsSchema": "{}\n", |
277 | 277 | "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\":\"Update double timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" |
... | ... | @@ -285,9 +285,9 @@ |
285 | 285 | "sizeX": 7.5, |
286 | 286 | "sizeY": 3, |
287 | 287 | "resources": [], |
288 | - "templateHtml": "<form class=\"attribute-update-form\"\n name=\"attrUpdateForm\"\n ng-submit=\"updateAttribute($event)\"\n>\n <div style=\"padding: 0 8px; margin: auto 0;\">\n\n <div class=\"attribute-update-form__grid\" ng-show=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <md-input-container ng-class=\"{'show-label': settings.showLabel}\" class=\"md-block\" style=\"width: 100%;\">\n <label>{{labelValue}}</label>\n <input required\n name=\"attribute\"\n ng-model=\"currentValue\"\n ng-focus=\"isFocused = true\"\n ng-blur=\"changeFocus()\"\n type=\"number\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"\n >\n <div ng-messages=\"attrUpdateForm.attribute.$error\">\n <div ng-message=\"required\">{{requiredErrorMessage}}</div>\n </div>\n </md-input-container>\n </div>\n\n <div class=\"grid__element\">\n <md-button class=\"md-icon-button applyChanges\"\n aria-label=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n type=\"submit\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"isFocused = false\"\n >\n <md-icon>check</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.update-timeseries' | translate }}</md-tooltip>\n </md-button>\n <md-button class=\"md-icon-button discardChanges\"\n aria-label=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n ng-disabled=\"originalValue === currentValue\"\n ng-click=\"currentValue = originalValue; isFocused = false\"\n >\n <md-icon>close</md-icon>\n <md-tooltip md-direction=\"top\">{{ 'widgets.input-widgets.discard-changes' | translate }}</md-tooltip>\n </md-button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-hide=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" ng-show=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n</form>", | |
289 | - "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.entity-title {\n font-weight: bold;\n font-size: 22px;\n padding-top: 12px;\n padding-bottom: 6px;\n color: #666;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .md-button.md-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .md-icon-button md-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.show-label label {\n display: block;\n}\n\nlabel {\n display: none;\n}\n\nmd-toast{\n min-width: 0;\n}\nmd-toast .md-toast-content {\n font-size: 14px!important;\n}", | |
290 | - "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet toast;\nlet utils;\nlet types;\nlet $translate;\nlet $q;\nlet $http;\n\nself.onInit = function() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get('attributeService');\n toast = $scope.$injector.get('toast');\n utils = $scope.$injector.get('utils');\n types = $scope.$injector.get('types');\n $translate = $scope.$injector.get('$translate');\n $q = $scope.$injector.get('$q');\n $http = $scope.$injector.get('$http');\n settings = angular.copy(self.ctx.settings) || {};\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || $translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || $translate.instant('widgets.input-widgets.value');\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === types.datasourceType.entity) {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type != types.dataKeyType.timeseries) {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n saveEntityTimeseries(\n datasource.entityType,\n datasource.entityId,\n [\n {\n key: $scope.currentKey,\n value: $scope.currentValue\n }\n ]\n ).then(\n function success() {\n $scope.originalValue = $scope.currentValue;\n if (settings.showResultMessage) {\n toast.showSuccess($translate.instant('widgets.input-widgets.update-successful'), 1000, angular.element(self.ctx.$container), 'bottom left');\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n toast.showError($translate.instant('widgets.input-widgets.update-failed'), angular.element(self.ctx.$container), 'bottom left');\n }\n }\n );\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.currentValue === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n\n function saveEntityTimeseries(entityType, entityId, telemetries) {\n var deferred = $q.defer();\n var telemetriesData = {};\n for (var a = 0; a < telemetries.length; a++) {\n if (angular.isDefined(telemetries[a].value) && telemetries[a].value !== null) {\n telemetriesData[telemetries[a].key] = telemetries[a].value;\n }\n }\n if (Object.keys(telemetriesData).length) {\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\n $http.post(url, telemetriesData).then(\n function(response) {\n deferred.resolve(response.data);\n },\n function() {\n deferred.reject();\n }\n );\n }\n return deferred.promise;\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.currentValue = $scope.originalValue = self.ctx.data[0].data[0][1];\n correctValue($scope.currentValue);\n $scope.$digest();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n $scope.currentValue = 0;\n }\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
288 | + "templateHtml": "<div tb-toast toastTarget=\"{{ toastTargetId }}\" style=\"width: 100%; height: 100%;\">\n<form *ngIf=\"attributeUpdateFormGroup\"\n class=\"attribute-update-form\"\n [formGroup]=\"attributeUpdateFormGroup\"\n (ngSubmit)=\"updateAttribute()\">\n <div style=\"padding: 0 8px; margin: auto 0;\">\n <div class=\"attribute-update-form__grid\" [fxShow]=\"entityDetected && isValidParameter && dataKeyDetected\">\n <div class=\"grid__element\">\n <mat-form-field class=\"mat-block\" style=\"width: 100%;\"\n floatLabel=\"{{settings.showLabel ? 'auto' : 'always'}}\"\n [hideRequiredMarker]=\"!settings.showLabel\">\n <mat-label>{{ settings.showLabel ? labelValue : '' }}</mat-label>\n <input matInput\n formControlName=\"currentValue\"\n required\n type=\"number\"\n step=\"1\"\n pattern=\"^-?[0-9]+$\"\n (focus)=\"isFocused = true\"\n (blur)=\"changeFocus()\"\n max=\"{{settings.maxValue}}\"\n min=\"{{settings.minValue}}\"/>\n <mat-error *ngIf=\"attributeUpdateFormGroup.get('currentValue').hasError('required')\">\n {{requiredErrorMessage}}\n </mat-error>\n </mat-form-field> \n </div>\n\n <div class=\"grid__element\">\n <button mat-button mat-icon-button class=\"applyChanges\"\n type=\"submit\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value || attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty\"\n matTooltip=\"{{ 'widgets.input-widgets.update-timeseries' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>check</mat-icon>\n </button>\n <button mat-button mat-icon-button class=\"discardChanges\"\n type=\"button\"\n [disabled]=\"originalValue === attributeUpdateFormGroup.get('currentValue').value\"\n (click)=\"attributeUpdateFormGroup.get('currentValue').patchValue(originalValue); isFocused = false\"\n matTooltip=\"{{ 'widgets.input-widgets.discard-changes' | translate }}\"\n matTooltipPosition=\"above\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxHide]=\"entityDetected\">\n {{ 'widgets.input-widgets.no-entity-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxShow]=\"entityDetected && !dataKeyDetected\">\n {{ 'widgets.input-widgets.no-timeseries-selected' | translate }}\n </div>\n <div style=\"text-align: center; font-size: 18px; color: #a0a0a0;\" [fxShow]=\"entityDetected && !isValidParameter\">\n {{ 'widgets.input-widgets.attribute-not-allowed' | translate }}\n </div>\n </div>\n</form>\n</div>", | |
289 | + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n margin: 0;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}\n", | |
290 | + "controllerScript": "let $scope;\nlet settings;\nlet attributeService;\nlet utils;\nlet translate;\nlet http;\n\nself.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges(true);\n });\n};\n\n\nfunction init() {\n\n $scope = self.ctx.$scope;\n attributeService = $scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n utils = $scope.$injector.get(self.ctx.servicesMap.get('utils'));\n translate = $scope.$injector.get(self.ctx.servicesMap.get('translate'));\n http = $scope.$injector.get(self.ctx.servicesMap.get('http'));\n $scope.toastTargetId = 'input-widget' + utils.guid();\n settings = utils.deepClone(self.ctx.settings) || {};\n settings.showLabel = utils.defaultValue(settings.showLabel, true);\n settings.showResultMessage = utils.defaultValue(settings.showResultMessage, true);\n $scope.settings = settings;\n $scope.isValidParameter = true;\n $scope.dataKeyDetected = false;\n $scope.requiredErrorMessage = utils.customTranslation(settings.requiredErrorMessage, settings.requiredErrorMessage) || translate.instant('widgets.input-widgets.entity-timeseries-required');\n $scope.labelValue = utils.customTranslation(settings.labelValue, settings.labelValue) || translate.instant('widgets.input-widgets.value');\n\n $scope.attributeUpdateFormGroup = $scope.fb.group(\n {currentValue: [undefined, [$scope.validators.required,\n $scope.validators.min(settings.minValue),\n $scope.validators.max(settings.maxValue),\n $scope.validators.pattern(/^-?[0-9]+$/)]]}\n );\n\n if (self.ctx.datasources && self.ctx.datasources.length) {\n var datasource = self.ctx.datasources[0];\n if (datasource.type === 'entity') {\n if (datasource.entityType && datasource.entityId) {\n $scope.entityName = datasource.entityName;\n if (settings.widgetTitle && settings.widgetTitle.length) {\n $scope.titleTemplate = utils.customTranslation(settings.widgetTitle, settings.widgetTitle);\n } else {\n $scope.titleTemplate = self.ctx.widgetConfig.title;\n }\n\n $scope.entityDetected = true;\n }\n }\n if (datasource.dataKeys.length) {\n if (datasource.dataKeys[0].type !== \"timeseries\") {\n $scope.isValidParameter = false;\n } else {\n $scope.currentKey = datasource.dataKeys[0].name;\n $scope.dataKeyType = datasource.dataKeys[0].type;\n $scope.dataKeyDetected = true;\n }\n }\n }\n\n self.ctx.widgetTitle = utils.createLabelFromDatasource(self.ctx.datasources[0], $scope.titleTemplate);\n\n $scope.updateAttribute = function () {\n $scope.isFocused = false;\n if ($scope.entityDetected) {\n var datasource = self.ctx.datasources[0];\n\n let observable = saveEntityTimeseries(\n datasource.entityType,\n datasource.entityId,\n [\n {\n key: $scope.currentKey,\n value: $scope.attributeUpdateFormGroup.get('currentValue').value\n }\n ]\n );\n if (observable) {\n observable.subscribe(\n function success() {\n $scope.originalValue = $scope.attributeUpdateFormGroup.get('currentValue').value;\n if (settings.showResultMessage) {\n $scope.showSuccessToast(translate.instant('widgets.input-widgets.update-successful'), 1000, 'bottom', 'left', $scope.toastTargetId);\n }\n },\n function fail() {\n if (settings.showResultMessage) {\n $scope.showErrorToast(translate.instant('widgets.input-widgets.update-failed'), 'bottom', 'left', $scope.toastTargetId);\n }\n }\n );\n }\n }\n };\n\n $scope.changeFocus = function () {\n if ($scope.attributeUpdateFormGroup.get('currentValue').value === $scope.originalValue) {\n $scope.isFocused = false;\n }\n }\n\n function saveEntityTimeseries(entityType, entityId, telemetries) {\n var telemetriesData = {};\n for (var a = 0; a < telemetries.length; a++) {\n if (typeof telemetries[a].value !== 'undefined' && telemetries[a].value !== null) {\n telemetriesData[telemetries[a].key] = telemetries[a].value;\n }\n }\n if (Object.keys(telemetriesData).length) {\n var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/scope';\n return http.post(url, telemetriesData);\n }\n return null;\n }\n}\n\nself.onDataUpdated = function() {\n\n try {\n if ($scope.dataKeyDetected) {\n if (!$scope.isFocused) {\n $scope.originalValue = self.ctx.data[0].data[0][1];\n $scope.attributeUpdateFormGroup.get('currentValue').patchValue(correctValue($scope.originalValue));\n self.ctx.detectChanges();\n }\n }\n } catch (e) {\n console.log(e);\n }\n}\n\nfunction correctValue(value) {\n if (typeof value !== \"number\") {\n return 0;\n }\n return value;\n}\n\nself.onResize = function() {\n\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n dataKeyOptional: true\n }\n}\n\nself.onDestroy = function() {\n\n}\n", | |
291 | 291 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EntitiesTableSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showLabel\":{\n \"title\":\"Show label\",\n \"type\":\"boolean\",\n \"default\":true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"requiredErrorMessage\": {\n \"title\": \"'Required' error message\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"maxValue\": {\n \"title\": \"Max value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"minValue\": {\n \"title\": \"Min value\",\n \"type\": \"number\",\n \"default\": \"\"\n },\n \"showResultMessage\":{\n \"title\":\"Show result message\",\n \"type\":\"boolean\",\n \"default\":true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n \"showResultMessage\",\n \"showLabel\",\n \"labelValue\",\n \"requiredErrorMessage\",\n \"maxValue\",\n \"minValue\"\n ]\n}", |
292 | 292 | "dataKeySettingsSchema": "{}\n", |
293 | 293 | "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\":\"Update integer timeseries\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
... | ... | @@ -18,8 +18,8 @@ package org.thingsboard.server.actors.shared.rulechain; |
18 | 18 | import org.thingsboard.server.actors.ActorSystemContext; |
19 | 19 | import org.thingsboard.server.actors.service.DefaultActorService; |
20 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
21 | +import org.thingsboard.server.common.data.page.PageData; | |
21 | 22 | import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; |
22 | -import org.thingsboard.server.common.data.page.TextPageData; | |
23 | 23 | import org.thingsboard.server.common.data.rule.RuleChain; |
24 | 24 | import org.thingsboard.server.dao.model.ModelConstants; |
25 | 25 | |
... | ... | @@ -33,7 +33,7 @@ public class SystemRuleChainManager extends RuleChainManager { |
33 | 33 | |
34 | 34 | @Override |
35 | 35 | protected FetchFunction<RuleChain> getFetchEntitiesFunction() { |
36 | - return link -> new TextPageData<>(Collections.emptyList(), link); | |
36 | + return link -> new PageData<>(); | |
37 | 37 | } |
38 | 38 | |
39 | 39 | @Override | ... | ... |
... | ... | @@ -68,7 +68,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
68 | 68 | public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; |
69 | 69 | public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; |
70 | 70 | public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; |
71 | - protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/static/**", "/api/noauth/**", "/webjars/**"}; | |
71 | + protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**"}; | |
72 | 72 | public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; |
73 | 73 | public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; |
74 | 74 | |
... | ... | @@ -155,7 +155,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
155 | 155 | |
156 | 156 | @Override |
157 | 157 | public void configure(WebSecurity web) throws Exception { |
158 | - web.ignoring().antMatchers("/static/**"); | |
158 | + web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**"); | |
159 | 159 | } |
160 | 160 | |
161 | 161 | @Override | ... | ... |
... | ... | @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping; |
21 | 21 | @Controller |
22 | 22 | public class WebConfig { |
23 | 23 | |
24 | - @RequestMapping(value = "/{path:^(?!api$)(?!static$)(?!webjars$)[^\\.]*}/**") | |
24 | + @RequestMapping(value = "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)[^\\.]*}/**") | |
25 | 25 | public String redirect() { |
26 | 26 | return "forward:/index.html"; |
27 | 27 | } | ... | ... |
... | ... | @@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
39 | 39 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
40 | 40 | import org.thingsboard.server.common.data.id.EntityId; |
41 | 41 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
42 | -import org.thingsboard.server.common.data.page.TimePageData; | |
42 | +import org.thingsboard.server.common.data.page.PageData; | |
43 | 43 | import org.thingsboard.server.common.data.page.TimePageLink; |
44 | 44 | import org.thingsboard.server.service.security.permission.Operation; |
45 | 45 | import org.thingsboard.server.service.security.permission.Resource; |
... | ... | @@ -143,16 +143,18 @@ public class AlarmController extends BaseController { |
143 | 143 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
144 | 144 | @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET) |
145 | 145 | @ResponseBody |
146 | - public TimePageData<AlarmInfo> getAlarms( | |
146 | + public PageData<AlarmInfo> getAlarms( | |
147 | 147 | @PathVariable("entityType") String strEntityType, |
148 | 148 | @PathVariable("entityId") String strEntityId, |
149 | 149 | @RequestParam(required = false) String searchStatus, |
150 | 150 | @RequestParam(required = false) String status, |
151 | - @RequestParam int limit, | |
151 | + @RequestParam int pageSize, | |
152 | + @RequestParam int page, | |
153 | + @RequestParam(required = false) String textSearch, | |
154 | + @RequestParam(required = false) String sortProperty, | |
155 | + @RequestParam(required = false) String sortOrder, | |
152 | 156 | @RequestParam(required = false) Long startTime, |
153 | 157 | @RequestParam(required = false) Long endTime, |
154 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
155 | - @RequestParam(required = false) String offset, | |
156 | 158 | @RequestParam(required = false) Boolean fetchOriginator |
157 | 159 | ) throws ThingsboardException { |
158 | 160 | checkParameter("EntityId", strEntityId); |
... | ... | @@ -165,8 +167,8 @@ public class AlarmController extends BaseController { |
165 | 167 | "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
166 | 168 | } |
167 | 169 | checkEntityId(entityId, Operation.READ); |
170 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
168 | 171 | try { |
169 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
170 | 172 | return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); |
171 | 173 | } catch (Exception e) { |
172 | 174 | throw handleException(e); | ... | ... |
... | ... | @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.Customer; |
30 | 30 | import org.thingsboard.server.common.data.EntitySubtype; |
31 | 31 | import org.thingsboard.server.common.data.EntityType; |
32 | 32 | import org.thingsboard.server.common.data.asset.Asset; |
33 | +import org.thingsboard.server.common.data.asset.AssetInfo; | |
33 | 34 | import org.thingsboard.server.common.data.asset.AssetSearchQuery; |
34 | 35 | import org.thingsboard.server.common.data.audit.ActionType; |
35 | 36 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
... | ... | @@ -37,8 +38,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; |
37 | 38 | import org.thingsboard.server.common.data.id.AssetId; |
38 | 39 | import org.thingsboard.server.common.data.id.CustomerId; |
39 | 40 | import org.thingsboard.server.common.data.id.TenantId; |
40 | -import org.thingsboard.server.common.data.page.TextPageData; | |
41 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
41 | +import org.thingsboard.server.common.data.page.PageData; | |
42 | +import org.thingsboard.server.common.data.page.PageLink; | |
42 | 43 | import org.thingsboard.server.common.data.security.Authority; |
43 | 44 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
44 | 45 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -70,6 +71,19 @@ public class AssetController extends BaseController { |
70 | 71 | } |
71 | 72 | |
72 | 73 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
74 | + @RequestMapping(value = "/asset/info/{assetId}", method = RequestMethod.GET) | |
75 | + @ResponseBody | |
76 | + public AssetInfo getAssetInfoById(@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { | |
77 | + checkParameter(ASSET_ID, strAssetId); | |
78 | + try { | |
79 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | |
80 | + return checkAssetInfoId(assetId, Operation.READ); | |
81 | + } catch (Exception e) { | |
82 | + throw handleException(e); | |
83 | + } | |
84 | + } | |
85 | + | |
86 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
73 | 87 | @RequestMapping(value = "/asset", method = RequestMethod.POST) |
74 | 88 | @ResponseBody |
75 | 89 | public Asset saveAsset(@RequestBody Asset asset) throws ThingsboardException { |
... | ... | @@ -207,17 +221,18 @@ public class AssetController extends BaseController { |
207 | 221 | } |
208 | 222 | |
209 | 223 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
210 | - @RequestMapping(value = "/tenant/assets", params = {"limit"}, method = RequestMethod.GET) | |
224 | + @RequestMapping(value = "/tenant/assets", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
211 | 225 | @ResponseBody |
212 | - public TextPageData<Asset> getTenantAssets( | |
213 | - @RequestParam int limit, | |
226 | + public PageData<Asset> getTenantAssets( | |
227 | + @RequestParam int pageSize, | |
228 | + @RequestParam int page, | |
214 | 229 | @RequestParam(required = false) String type, |
215 | 230 | @RequestParam(required = false) String textSearch, |
216 | - @RequestParam(required = false) String idOffset, | |
217 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
231 | + @RequestParam(required = false) String sortProperty, | |
232 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
218 | 233 | try { |
219 | 234 | TenantId tenantId = getCurrentUser().getTenantId(); |
220 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
235 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
221 | 236 | if (type != null && type.trim().length()>0) { |
222 | 237 | return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink)); |
223 | 238 | } else { |
... | ... | @@ -229,6 +244,29 @@ public class AssetController extends BaseController { |
229 | 244 | } |
230 | 245 | |
231 | 246 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
247 | + @RequestMapping(value = "/tenant/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
248 | + @ResponseBody | |
249 | + public PageData<AssetInfo> getTenantAssetInfos( | |
250 | + @RequestParam int pageSize, | |
251 | + @RequestParam int page, | |
252 | + @RequestParam(required = false) String type, | |
253 | + @RequestParam(required = false) String textSearch, | |
254 | + @RequestParam(required = false) String sortProperty, | |
255 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
256 | + try { | |
257 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
258 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
259 | + if (type != null && type.trim().length() > 0) { | |
260 | + return checkNotNull(assetService.findAssetInfosByTenantIdAndType(tenantId, type, pageLink)); | |
261 | + } else { | |
262 | + return checkNotNull(assetService.findAssetInfosByTenantId(tenantId, pageLink)); | |
263 | + } | |
264 | + } catch (Exception e) { | |
265 | + throw handleException(e); | |
266 | + } | |
267 | + } | |
268 | + | |
269 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
232 | 270 | @RequestMapping(value = "/tenant/assets", params = {"assetName"}, method = RequestMethod.GET) |
233 | 271 | @ResponseBody |
234 | 272 | public Asset getTenantAsset( |
... | ... | @@ -242,21 +280,22 @@ public class AssetController extends BaseController { |
242 | 280 | } |
243 | 281 | |
244 | 282 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
245 | - @RequestMapping(value = "/customer/{customerId}/assets", params = {"limit"}, method = RequestMethod.GET) | |
283 | + @RequestMapping(value = "/customer/{customerId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
246 | 284 | @ResponseBody |
247 | - public TextPageData<Asset> getCustomerAssets( | |
285 | + public PageData<Asset> getCustomerAssets( | |
248 | 286 | @PathVariable("customerId") String strCustomerId, |
249 | - @RequestParam int limit, | |
287 | + @RequestParam int pageSize, | |
288 | + @RequestParam int page, | |
250 | 289 | @RequestParam(required = false) String type, |
251 | 290 | @RequestParam(required = false) String textSearch, |
252 | - @RequestParam(required = false) String idOffset, | |
253 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
291 | + @RequestParam(required = false) String sortProperty, | |
292 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
254 | 293 | checkParameter("customerId", strCustomerId); |
255 | 294 | try { |
256 | 295 | TenantId tenantId = getCurrentUser().getTenantId(); |
257 | 296 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
258 | 297 | checkCustomerId(customerId, Operation.READ); |
259 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
298 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
260 | 299 | if (type != null && type.trim().length()>0) { |
261 | 300 | return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); |
262 | 301 | } else { |
... | ... | @@ -268,6 +307,33 @@ public class AssetController extends BaseController { |
268 | 307 | } |
269 | 308 | |
270 | 309 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
310 | + @RequestMapping(value = "/customer/{customerId}/assetInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
311 | + @ResponseBody | |
312 | + public PageData<AssetInfo> getCustomerAssetInfos( | |
313 | + @PathVariable("customerId") String strCustomerId, | |
314 | + @RequestParam int pageSize, | |
315 | + @RequestParam int page, | |
316 | + @RequestParam(required = false) String type, | |
317 | + @RequestParam(required = false) String textSearch, | |
318 | + @RequestParam(required = false) String sortProperty, | |
319 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
320 | + checkParameter("customerId", strCustomerId); | |
321 | + try { | |
322 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
323 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
324 | + checkCustomerId(customerId, Operation.READ); | |
325 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
326 | + if (type != null && type.trim().length() > 0) { | |
327 | + return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); | |
328 | + } else { | |
329 | + return checkNotNull(assetService.findAssetInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
330 | + } | |
331 | + } catch (Exception e) { | |
332 | + throw handleException(e); | |
333 | + } | |
334 | + } | |
335 | + | |
336 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
271 | 337 | @RequestMapping(value = "/assets", params = {"assetIds"}, method = RequestMethod.GET) |
272 | 338 | @ResponseBody |
273 | 339 | public List<Asset> getAssetsByIds( | ... | ... |
... | ... | @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.id.CustomerId; |
30 | 30 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
31 | 31 | import org.thingsboard.server.common.data.id.TenantId; |
32 | 32 | import org.thingsboard.server.common.data.id.UserId; |
33 | -import org.thingsboard.server.common.data.page.TimePageData; | |
33 | +import org.thingsboard.server.common.data.page.PageData; | |
34 | 34 | import org.thingsboard.server.common.data.page.TimePageLink; |
35 | 35 | |
36 | 36 | import java.util.Arrays; |
... | ... | @@ -43,20 +43,22 @@ import java.util.stream.Collectors; |
43 | 43 | public class AuditLogController extends BaseController { |
44 | 44 | |
45 | 45 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
46 | - @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"limit"}, method = RequestMethod.GET) | |
46 | + @RequestMapping(value = "/audit/logs/customer/{customerId}", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
47 | 47 | @ResponseBody |
48 | - public TimePageData<AuditLog> getAuditLogsByCustomerId( | |
48 | + public PageData<AuditLog> getAuditLogsByCustomerId( | |
49 | 49 | @PathVariable("customerId") String strCustomerId, |
50 | - @RequestParam int limit, | |
50 | + @RequestParam int pageSize, | |
51 | + @RequestParam int page, | |
52 | + @RequestParam(required = false) String textSearch, | |
53 | + @RequestParam(required = false) String sortProperty, | |
54 | + @RequestParam(required = false) String sortOrder, | |
51 | 55 | @RequestParam(required = false) Long startTime, |
52 | 56 | @RequestParam(required = false) Long endTime, |
53 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
54 | - @RequestParam(required = false) String offset, | |
55 | 57 | @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { |
56 | 58 | try { |
57 | 59 | checkParameter("CustomerId", strCustomerId); |
58 | 60 | TenantId tenantId = getCurrentUser().getTenantId(); |
59 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
61 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
60 | 62 | List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr); |
61 | 63 | return checkNotNull(auditLogService.findAuditLogsByTenantIdAndCustomerId(tenantId, new CustomerId(UUID.fromString(strCustomerId)), actionTypes, pageLink)); |
62 | 64 | } catch (Exception e) { |
... | ... | @@ -65,20 +67,22 @@ public class AuditLogController extends BaseController { |
65 | 67 | } |
66 | 68 | |
67 | 69 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
68 | - @RequestMapping(value = "/audit/logs/user/{userId}", params = {"limit"}, method = RequestMethod.GET) | |
70 | + @RequestMapping(value = "/audit/logs/user/{userId}", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
69 | 71 | @ResponseBody |
70 | - public TimePageData<AuditLog> getAuditLogsByUserId( | |
72 | + public PageData<AuditLog> getAuditLogsByUserId( | |
71 | 73 | @PathVariable("userId") String strUserId, |
72 | - @RequestParam int limit, | |
74 | + @RequestParam int pageSize, | |
75 | + @RequestParam int page, | |
76 | + @RequestParam(required = false) String textSearch, | |
77 | + @RequestParam(required = false) String sortProperty, | |
78 | + @RequestParam(required = false) String sortOrder, | |
73 | 79 | @RequestParam(required = false) Long startTime, |
74 | 80 | @RequestParam(required = false) Long endTime, |
75 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
76 | - @RequestParam(required = false) String offset, | |
77 | 81 | @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { |
78 | 82 | try { |
79 | 83 | checkParameter("UserId", strUserId); |
80 | 84 | TenantId tenantId = getCurrentUser().getTenantId(); |
81 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
85 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
82 | 86 | List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr); |
83 | 87 | return checkNotNull(auditLogService.findAuditLogsByTenantIdAndUserId(tenantId, new UserId(UUID.fromString(strUserId)), actionTypes, pageLink)); |
84 | 88 | } catch (Exception e) { |
... | ... | @@ -87,22 +91,24 @@ public class AuditLogController extends BaseController { |
87 | 91 | } |
88 | 92 | |
89 | 93 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
90 | - @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"limit"}, method = RequestMethod.GET) | |
94 | + @RequestMapping(value = "/audit/logs/entity/{entityType}/{entityId}", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
91 | 95 | @ResponseBody |
92 | - public TimePageData<AuditLog> getAuditLogsByEntityId( | |
96 | + public PageData<AuditLog> getAuditLogsByEntityId( | |
93 | 97 | @PathVariable("entityType") String strEntityType, |
94 | 98 | @PathVariable("entityId") String strEntityId, |
95 | - @RequestParam int limit, | |
99 | + @RequestParam int pageSize, | |
100 | + @RequestParam int page, | |
101 | + @RequestParam(required = false) String textSearch, | |
102 | + @RequestParam(required = false) String sortProperty, | |
103 | + @RequestParam(required = false) String sortOrder, | |
96 | 104 | @RequestParam(required = false) Long startTime, |
97 | 105 | @RequestParam(required = false) Long endTime, |
98 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
99 | - @RequestParam(required = false) String offset, | |
100 | 106 | @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { |
101 | 107 | try { |
102 | 108 | checkParameter("EntityId", strEntityId); |
103 | 109 | checkParameter("EntityType", strEntityType); |
104 | 110 | TenantId tenantId = getCurrentUser().getTenantId(); |
105 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
111 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
106 | 112 | List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr); |
107 | 113 | return checkNotNull(auditLogService.findAuditLogsByTenantIdAndEntityId(tenantId, EntityIdFactory.getByTypeAndId(strEntityType, strEntityId), actionTypes, pageLink)); |
108 | 114 | } catch (Exception e) { |
... | ... | @@ -111,19 +117,21 @@ public class AuditLogController extends BaseController { |
111 | 117 | } |
112 | 118 | |
113 | 119 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
114 | - @RequestMapping(value = "/audit/logs", params = {"limit"}, method = RequestMethod.GET) | |
120 | + @RequestMapping(value = "/audit/logs", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
115 | 121 | @ResponseBody |
116 | - public TimePageData<AuditLog> getAuditLogs( | |
117 | - @RequestParam int limit, | |
122 | + public PageData<AuditLog> getAuditLogs( | |
123 | + @RequestParam int pageSize, | |
124 | + @RequestParam int page, | |
125 | + @RequestParam(required = false) String textSearch, | |
126 | + @RequestParam(required = false) String sortProperty, | |
127 | + @RequestParam(required = false) String sortOrder, | |
118 | 128 | @RequestParam(required = false) Long startTime, |
119 | 129 | @RequestParam(required = false) Long endTime, |
120 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
121 | - @RequestParam(required = false) String offset, | |
122 | 130 | @RequestParam(name = "actionTypes", required = false) String actionTypesStr) throws ThingsboardException { |
123 | 131 | try { |
124 | 132 | TenantId tenantId = getCurrentUser().getTenantId(); |
125 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
126 | 133 | List<ActionType> actionTypes = parseActionTypesStr(actionTypesStr); |
134 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
127 | 135 | return checkNotNull(auditLogService.findAuditLogsByTenantId(tenantId, actionTypes, pageLink)); |
128 | 136 | } catch (Exception e) { |
129 | 137 | throw handleException(e); | ... | ... |
... | ... | @@ -28,20 +28,12 @@ import org.springframework.security.core.Authentication; |
28 | 28 | import org.springframework.security.core.context.SecurityContextHolder; |
29 | 29 | import org.springframework.web.bind.annotation.ExceptionHandler; |
30 | 30 | import org.thingsboard.server.actors.service.ActorService; |
31 | -import org.thingsboard.server.common.data.Customer; | |
32 | -import org.thingsboard.server.common.data.Dashboard; | |
33 | -import org.thingsboard.server.common.data.DashboardInfo; | |
34 | -import org.thingsboard.server.common.data.DataConstants; | |
35 | -import org.thingsboard.server.common.data.Device; | |
36 | -import org.thingsboard.server.common.data.EntityType; | |
37 | -import org.thingsboard.server.common.data.EntityView; | |
38 | -import org.thingsboard.server.common.data.HasName; | |
39 | -import org.thingsboard.server.common.data.Tenant; | |
40 | -import org.thingsboard.server.common.data.User; | |
31 | +import org.thingsboard.server.common.data.*; | |
41 | 32 | import org.thingsboard.server.common.data.alarm.Alarm; |
42 | 33 | import org.thingsboard.server.common.data.alarm.AlarmId; |
43 | 34 | import org.thingsboard.server.common.data.alarm.AlarmInfo; |
44 | 35 | import org.thingsboard.server.common.data.asset.Asset; |
36 | +import org.thingsboard.server.common.data.asset.AssetInfo; | |
45 | 37 | import org.thingsboard.server.common.data.audit.ActionType; |
46 | 38 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
47 | 39 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
... | ... | @@ -60,7 +52,8 @@ import org.thingsboard.server.common.data.id.WidgetTypeId; |
60 | 52 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
61 | 53 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
62 | 54 | import org.thingsboard.server.common.data.kv.DataType; |
63 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
55 | +import org.thingsboard.server.common.data.page.PageLink; | |
56 | +import org.thingsboard.server.common.data.page.SortOrder; | |
64 | 57 | import org.thingsboard.server.common.data.page.TimePageLink; |
65 | 58 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
66 | 59 | import org.thingsboard.server.common.data.plugin.ComponentType; |
... | ... | @@ -256,21 +249,27 @@ public abstract class BaseController { |
256 | 249 | return UUID.fromString(id); |
257 | 250 | } |
258 | 251 | |
259 | - TimePageLink createPageLink(int limit, Long startTime, Long endTime, boolean ascOrder, String idOffset) { | |
260 | - UUID idOffsetUuid = null; | |
261 | - if (StringUtils.isNotEmpty(idOffset)) { | |
262 | - idOffsetUuid = toUUID(idOffset); | |
252 | + PageLink createPageLink(int pageSize, int page, String textSearch, String sortProperty, String sortOrder) throws ThingsboardException { | |
253 | + if (!StringUtils.isEmpty(sortProperty)) { | |
254 | + SortOrder.Direction direction = SortOrder.Direction.ASC; | |
255 | + if (!StringUtils.isEmpty(sortOrder)) { | |
256 | + try { | |
257 | + direction = SortOrder.Direction.valueOf(sortOrder.toUpperCase()); | |
258 | + } catch (IllegalArgumentException e) { | |
259 | + throw new ThingsboardException("Unsupported sort order '" + sortOrder + "'! Only 'ASC' or 'DESC' types are allowed.", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
260 | + } | |
261 | + } | |
262 | + SortOrder sort = new SortOrder(sortProperty, direction); | |
263 | + return new PageLink(pageSize, page, textSearch, sort); | |
264 | + } else { | |
265 | + return new PageLink(pageSize, page, textSearch); | |
263 | 266 | } |
264 | - return new TimePageLink(limit, startTime, endTime, ascOrder, idOffsetUuid); | |
265 | 267 | } |
266 | 268 | |
267 | - | |
268 | - TextPageLink createPageLink(int limit, String textSearch, String idOffset, String textOffset) { | |
269 | - UUID idOffsetUuid = null; | |
270 | - if (StringUtils.isNotEmpty(idOffset)) { | |
271 | - idOffsetUuid = toUUID(idOffset); | |
272 | - } | |
273 | - return new TextPageLink(limit, textSearch, idOffsetUuid, textOffset); | |
269 | + TimePageLink createTimePageLink(int pageSize, int page, String textSearch, | |
270 | + String sortProperty, String sortOrder, Long startTime, Long endTime) throws ThingsboardException { | |
271 | + PageLink pageLink = this.createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
272 | + return new TimePageLink(pageLink, startTime, endTime); | |
274 | 273 | } |
275 | 274 | |
276 | 275 | protected SecurityUser getCurrentUser() throws ThingsboardException { |
... | ... | @@ -374,6 +373,18 @@ public abstract class BaseController { |
374 | 373 | } |
375 | 374 | } |
376 | 375 | |
376 | + DeviceInfo checkDeviceInfoId(DeviceId deviceId, Operation operation) throws ThingsboardException { | |
377 | + try { | |
378 | + validateId(deviceId, "Incorrect deviceId " + deviceId); | |
379 | + DeviceInfo device = deviceService.findDeviceInfoById(getCurrentUser().getTenantId(), deviceId); | |
380 | + checkNotNull(device); | |
381 | + accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device); | |
382 | + return device; | |
383 | + } catch (Exception e) { | |
384 | + throw handleException(e, false); | |
385 | + } | |
386 | + } | |
387 | + | |
377 | 388 | protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation) throws ThingsboardException { |
378 | 389 | try { |
379 | 390 | validateId(entityViewId, "Incorrect entityViewId " + entityViewId); |
... | ... | @@ -386,6 +397,18 @@ public abstract class BaseController { |
386 | 397 | } |
387 | 398 | } |
388 | 399 | |
400 | + EntityViewInfo checkEntityViewInfoId(EntityViewId entityViewId, Operation operation) throws ThingsboardException { | |
401 | + try { | |
402 | + validateId(entityViewId, "Incorrect entityViewId " + entityViewId); | |
403 | + EntityViewInfo entityView = entityViewService.findEntityViewInfoById(getCurrentUser().getTenantId(), entityViewId); | |
404 | + checkNotNull(entityView); | |
405 | + accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView); | |
406 | + return entityView; | |
407 | + } catch (Exception e) { | |
408 | + throw handleException(e, false); | |
409 | + } | |
410 | + } | |
411 | + | |
389 | 412 | Asset checkAssetId(AssetId assetId, Operation operation) throws ThingsboardException { |
390 | 413 | try { |
391 | 414 | validateId(assetId, "Incorrect assetId " + assetId); |
... | ... | @@ -398,6 +421,18 @@ public abstract class BaseController { |
398 | 421 | } |
399 | 422 | } |
400 | 423 | |
424 | + AssetInfo checkAssetInfoId(AssetId assetId, Operation operation) throws ThingsboardException { | |
425 | + try { | |
426 | + validateId(assetId, "Incorrect assetId " + assetId); | |
427 | + AssetInfo asset = assetService.findAssetInfoById(getCurrentUser().getTenantId(), assetId); | |
428 | + checkNotNull(asset); | |
429 | + accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset); | |
430 | + return asset; | |
431 | + } catch (Exception e) { | |
432 | + throw handleException(e, false); | |
433 | + } | |
434 | + } | |
435 | + | |
401 | 436 | Alarm checkAlarmId(AlarmId alarmId, Operation operation) throws ThingsboardException { |
402 | 437 | try { |
403 | 438 | validateId(alarmId, "Incorrect alarmId " + alarmId); | ... | ... |
... | ... | @@ -34,8 +34,8 @@ import org.thingsboard.server.common.data.audit.ActionType; |
34 | 34 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
35 | 35 | import org.thingsboard.server.common.data.id.CustomerId; |
36 | 36 | import org.thingsboard.server.common.data.id.TenantId; |
37 | -import org.thingsboard.server.common.data.page.TextPageData; | |
38 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
37 | +import org.thingsboard.server.common.data.page.PageData; | |
38 | +import org.thingsboard.server.common.data.page.PageLink; | |
39 | 39 | import org.thingsboard.server.service.security.permission.Operation; |
40 | 40 | import org.thingsboard.server.service.security.permission.Resource; |
41 | 41 | |
... | ... | @@ -143,14 +143,15 @@ public class CustomerController extends BaseController { |
143 | 143 | } |
144 | 144 | |
145 | 145 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
146 | - @RequestMapping(value = "/customers", params = {"limit"}, method = RequestMethod.GET) | |
146 | + @RequestMapping(value = "/customers", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
147 | 147 | @ResponseBody |
148 | - public TextPageData<Customer> getCustomers(@RequestParam int limit, | |
149 | - @RequestParam(required = false) String textSearch, | |
150 | - @RequestParam(required = false) String idOffset, | |
151 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
148 | + public PageData<Customer> getCustomers(@RequestParam int pageSize, | |
149 | + @RequestParam int page, | |
150 | + @RequestParam(required = false) String textSearch, | |
151 | + @RequestParam(required = false) String sortProperty, | |
152 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
152 | 153 | try { |
153 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
154 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
154 | 155 | TenantId tenantId = getCurrentUser().getTenantId(); |
155 | 156 | return checkNotNull(customerService.findCustomersByTenantId(tenantId, pageLink)); |
156 | 157 | } catch (Exception e) { | ... | ... |
... | ... | @@ -37,9 +37,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; |
37 | 37 | import org.thingsboard.server.common.data.id.CustomerId; |
38 | 38 | import org.thingsboard.server.common.data.id.DashboardId; |
39 | 39 | import org.thingsboard.server.common.data.id.TenantId; |
40 | -import org.thingsboard.server.common.data.page.TextPageData; | |
41 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
42 | -import org.thingsboard.server.common.data.page.TimePageData; | |
40 | +import org.thingsboard.server.common.data.page.PageData; | |
41 | +import org.thingsboard.server.common.data.page.PageLink; | |
43 | 42 | import org.thingsboard.server.common.data.page.TimePageLink; |
44 | 43 | import org.thingsboard.server.service.security.permission.Operation; |
45 | 44 | import org.thingsboard.server.service.security.permission.Resource; |
... | ... | @@ -417,18 +416,19 @@ public class DashboardController extends BaseController { |
417 | 416 | } |
418 | 417 | |
419 | 418 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
420 | - @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
419 | + @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
421 | 420 | @ResponseBody |
422 | - public TextPageData<DashboardInfo> getTenantDashboards( | |
421 | + public PageData<DashboardInfo> getTenantDashboards( | |
423 | 422 | @PathVariable("tenantId") String strTenantId, |
424 | - @RequestParam int limit, | |
423 | + @RequestParam int pageSize, | |
424 | + @RequestParam int page, | |
425 | 425 | @RequestParam(required = false) String textSearch, |
426 | - @RequestParam(required = false) String idOffset, | |
427 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
426 | + @RequestParam(required = false) String sortProperty, | |
427 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
428 | 428 | try { |
429 | 429 | TenantId tenantId = new TenantId(toUUID(strTenantId)); |
430 | 430 | checkTenantId(tenantId, Operation.READ); |
431 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
431 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
432 | 432 | return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); |
433 | 433 | } catch (Exception e) { |
434 | 434 | throw handleException(e); |
... | ... | @@ -436,16 +436,17 @@ public class DashboardController extends BaseController { |
436 | 436 | } |
437 | 437 | |
438 | 438 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
439 | - @RequestMapping(value = "/tenant/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
439 | + @RequestMapping(value = "/tenant/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
440 | 440 | @ResponseBody |
441 | - public TextPageData<DashboardInfo> getTenantDashboards( | |
442 | - @RequestParam int limit, | |
441 | + public PageData<DashboardInfo> getTenantDashboards( | |
442 | + @RequestParam int pageSize, | |
443 | + @RequestParam int page, | |
443 | 444 | @RequestParam(required = false) String textSearch, |
444 | - @RequestParam(required = false) String idOffset, | |
445 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
445 | + @RequestParam(required = false) String sortProperty, | |
446 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
446 | 447 | try { |
447 | 448 | TenantId tenantId = getCurrentUser().getTenantId(); |
448 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
449 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
449 | 450 | return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); |
450 | 451 | } catch (Exception e) { |
451 | 452 | throw handleException(e); |
... | ... | @@ -453,22 +454,22 @@ public class DashboardController extends BaseController { |
453 | 454 | } |
454 | 455 | |
455 | 456 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
456 | - @RequestMapping(value = "/customer/{customerId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
457 | + @RequestMapping(value = "/customer/{customerId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
457 | 458 | @ResponseBody |
458 | - public TimePageData<DashboardInfo> getCustomerDashboards( | |
459 | + public PageData<DashboardInfo> getCustomerDashboards( | |
459 | 460 | @PathVariable("customerId") String strCustomerId, |
460 | - @RequestParam int limit, | |
461 | - @RequestParam(required = false) Long startTime, | |
462 | - @RequestParam(required = false) Long endTime, | |
463 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
464 | - @RequestParam(required = false) String offset) throws ThingsboardException { | |
461 | + @RequestParam int pageSize, | |
462 | + @RequestParam int page, | |
463 | + @RequestParam(required = false) String textSearch, | |
464 | + @RequestParam(required = false) String sortProperty, | |
465 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
465 | 466 | checkParameter("customerId", strCustomerId); |
466 | 467 | try { |
467 | 468 | TenantId tenantId = getCurrentUser().getTenantId(); |
468 | 469 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
469 | 470 | checkCustomerId(customerId, Operation.READ); |
470 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
471 | - return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink).get()); | |
471 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
472 | + return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
472 | 473 | } catch (Exception e) { |
473 | 474 | throw handleException(e); |
474 | 475 | } | ... | ... |
... | ... | @@ -30,19 +30,15 @@ import org.springframework.web.bind.annotation.ResponseBody; |
30 | 30 | import org.springframework.web.bind.annotation.ResponseStatus; |
31 | 31 | import org.springframework.web.bind.annotation.RestController; |
32 | 32 | import org.springframework.web.context.request.async.DeferredResult; |
33 | -import org.thingsboard.server.common.data.Customer; | |
34 | -import org.thingsboard.server.common.data.DataConstants; | |
35 | -import org.thingsboard.server.common.data.Device; | |
36 | -import org.thingsboard.server.common.data.EntitySubtype; | |
37 | -import org.thingsboard.server.common.data.EntityType; | |
33 | +import org.thingsboard.server.common.data.*; | |
38 | 34 | import org.thingsboard.server.common.data.audit.ActionType; |
39 | 35 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
40 | 36 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
41 | 37 | import org.thingsboard.server.common.data.id.CustomerId; |
42 | 38 | import org.thingsboard.server.common.data.id.DeviceId; |
43 | 39 | import org.thingsboard.server.common.data.id.TenantId; |
44 | -import org.thingsboard.server.common.data.page.TextPageData; | |
45 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
40 | +import org.thingsboard.server.common.data.page.PageData; | |
41 | +import org.thingsboard.server.common.data.page.PageLink; | |
46 | 42 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
47 | 43 | import org.thingsboard.server.common.data.ClaimRequest; |
48 | 44 | import org.thingsboard.server.dao.device.claim.ClaimResponse; |
... | ... | @@ -80,6 +76,19 @@ public class DeviceController extends BaseController { |
80 | 76 | } |
81 | 77 | |
82 | 78 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
79 | + @RequestMapping(value = "/device/info/{deviceId}", method = RequestMethod.GET) | |
80 | + @ResponseBody | |
81 | + public DeviceInfo getDeviceInfoById(@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { | |
82 | + checkParameter(DEVICE_ID, strDeviceId); | |
83 | + try { | |
84 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | |
85 | + return checkDeviceInfoId(deviceId, Operation.READ); | |
86 | + } catch (Exception e) { | |
87 | + throw handleException(e); | |
88 | + } | |
89 | + } | |
90 | + | |
91 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
83 | 92 | @RequestMapping(value = "/device", method = RequestMethod.POST) |
84 | 93 | @ResponseBody |
85 | 94 | public Device saveDevice(@RequestBody Device device, |
... | ... | @@ -266,17 +275,18 @@ public class DeviceController extends BaseController { |
266 | 275 | } |
267 | 276 | |
268 | 277 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
269 | - @RequestMapping(value = "/tenant/devices", params = {"limit"}, method = RequestMethod.GET) | |
278 | + @RequestMapping(value = "/tenant/devices", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
270 | 279 | @ResponseBody |
271 | - public TextPageData<Device> getTenantDevices( | |
272 | - @RequestParam int limit, | |
280 | + public PageData<Device> getTenantDevices( | |
281 | + @RequestParam int pageSize, | |
282 | + @RequestParam int page, | |
273 | 283 | @RequestParam(required = false) String type, |
274 | 284 | @RequestParam(required = false) String textSearch, |
275 | - @RequestParam(required = false) String idOffset, | |
276 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
285 | + @RequestParam(required = false) String sortProperty, | |
286 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
277 | 287 | try { |
278 | 288 | TenantId tenantId = getCurrentUser().getTenantId(); |
279 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
289 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
280 | 290 | if (type != null && type.trim().length() > 0) { |
281 | 291 | return checkNotNull(deviceService.findDevicesByTenantIdAndType(tenantId, type, pageLink)); |
282 | 292 | } else { |
... | ... | @@ -288,6 +298,29 @@ public class DeviceController extends BaseController { |
288 | 298 | } |
289 | 299 | |
290 | 300 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
301 | + @RequestMapping(value = "/tenant/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
302 | + @ResponseBody | |
303 | + public PageData<DeviceInfo> getTenantDeviceInfos( | |
304 | + @RequestParam int pageSize, | |
305 | + @RequestParam int page, | |
306 | + @RequestParam(required = false) String type, | |
307 | + @RequestParam(required = false) String textSearch, | |
308 | + @RequestParam(required = false) String sortProperty, | |
309 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
310 | + try { | |
311 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
312 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
313 | + if (type != null && type.trim().length() > 0) { | |
314 | + return checkNotNull(deviceService.findDeviceInfosByTenantIdAndType(tenantId, type, pageLink)); | |
315 | + } else { | |
316 | + return checkNotNull(deviceService.findDeviceInfosByTenantId(tenantId, pageLink)); | |
317 | + } | |
318 | + } catch (Exception e) { | |
319 | + throw handleException(e); | |
320 | + } | |
321 | + } | |
322 | + | |
323 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
291 | 324 | @RequestMapping(value = "/tenant/devices", params = {"deviceName"}, method = RequestMethod.GET) |
292 | 325 | @ResponseBody |
293 | 326 | public Device getTenantDevice( |
... | ... | @@ -301,21 +334,22 @@ public class DeviceController extends BaseController { |
301 | 334 | } |
302 | 335 | |
303 | 336 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
304 | - @RequestMapping(value = "/customer/{customerId}/devices", params = {"limit"}, method = RequestMethod.GET) | |
337 | + @RequestMapping(value = "/customer/{customerId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
305 | 338 | @ResponseBody |
306 | - public TextPageData<Device> getCustomerDevices( | |
339 | + public PageData<Device> getCustomerDevices( | |
307 | 340 | @PathVariable("customerId") String strCustomerId, |
308 | - @RequestParam int limit, | |
341 | + @RequestParam int pageSize, | |
342 | + @RequestParam int page, | |
309 | 343 | @RequestParam(required = false) String type, |
310 | 344 | @RequestParam(required = false) String textSearch, |
311 | - @RequestParam(required = false) String idOffset, | |
312 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
345 | + @RequestParam(required = false) String sortProperty, | |
346 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
313 | 347 | checkParameter("customerId", strCustomerId); |
314 | 348 | try { |
315 | 349 | TenantId tenantId = getCurrentUser().getTenantId(); |
316 | 350 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
317 | 351 | checkCustomerId(customerId, Operation.READ); |
318 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
352 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
319 | 353 | if (type != null && type.trim().length() > 0) { |
320 | 354 | return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); |
321 | 355 | } else { |
... | ... | @@ -327,6 +361,33 @@ public class DeviceController extends BaseController { |
327 | 361 | } |
328 | 362 | |
329 | 363 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
364 | + @RequestMapping(value = "/customer/{customerId}/deviceInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
365 | + @ResponseBody | |
366 | + public PageData<DeviceInfo> getCustomerDeviceInfos( | |
367 | + @PathVariable("customerId") String strCustomerId, | |
368 | + @RequestParam int pageSize, | |
369 | + @RequestParam int page, | |
370 | + @RequestParam(required = false) String type, | |
371 | + @RequestParam(required = false) String textSearch, | |
372 | + @RequestParam(required = false) String sortProperty, | |
373 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
374 | + checkParameter("customerId", strCustomerId); | |
375 | + try { | |
376 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
377 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
378 | + checkCustomerId(customerId, Operation.READ); | |
379 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
380 | + if (type != null && type.trim().length() > 0) { | |
381 | + return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); | |
382 | + } else { | |
383 | + return checkNotNull(deviceService.findDeviceInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
384 | + } | |
385 | + } catch (Exception e) { | |
386 | + throw handleException(e); | |
387 | + } | |
388 | + } | |
389 | + | |
390 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
330 | 391 | @RequestMapping(value = "/devices", params = {"deviceIds"}, method = RequestMethod.GET) |
331 | 392 | @ResponseBody |
332 | 393 | public List<Device> getDevicesByIds( | ... | ... |
... | ... | @@ -29,11 +29,7 @@ import org.springframework.web.bind.annotation.RequestParam; |
29 | 29 | import org.springframework.web.bind.annotation.ResponseBody; |
30 | 30 | import org.springframework.web.bind.annotation.ResponseStatus; |
31 | 31 | import org.springframework.web.bind.annotation.RestController; |
32 | -import org.thingsboard.server.common.data.Customer; | |
33 | -import org.thingsboard.server.common.data.DataConstants; | |
34 | -import org.thingsboard.server.common.data.EntitySubtype; | |
35 | -import org.thingsboard.server.common.data.EntityType; | |
36 | -import org.thingsboard.server.common.data.EntityView; | |
32 | +import org.thingsboard.server.common.data.*; | |
37 | 33 | import org.thingsboard.server.common.data.audit.ActionType; |
38 | 34 | import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; |
39 | 35 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
... | ... | @@ -43,8 +39,8 @@ import org.thingsboard.server.common.data.id.EntityViewId; |
43 | 39 | import org.thingsboard.server.common.data.id.TenantId; |
44 | 40 | import org.thingsboard.server.common.data.id.UUIDBased; |
45 | 41 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
46 | -import org.thingsboard.server.common.data.page.TextPageData; | |
47 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
42 | +import org.thingsboard.server.common.data.page.PageData; | |
43 | +import org.thingsboard.server.common.data.page.PageLink; | |
48 | 44 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
49 | 45 | import org.thingsboard.server.dao.model.ModelConstants; |
50 | 46 | import org.thingsboard.server.service.security.model.SecurityUser; |
... | ... | @@ -83,6 +79,19 @@ public class EntityViewController extends BaseController { |
83 | 79 | } |
84 | 80 | |
85 | 81 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
82 | + @RequestMapping(value = "/entityView/info/{entityViewId}", method = RequestMethod.GET) | |
83 | + @ResponseBody | |
84 | + public EntityViewInfo getEntityViewInfoById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | |
85 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | |
86 | + try { | |
87 | + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | |
88 | + return checkEntityViewInfoId(entityViewId, Operation.READ); | |
89 | + } catch (Exception e) { | |
90 | + throw handleException(e); | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
86 | 95 | @RequestMapping(value = "/entityView", method = RequestMethod.POST) |
87 | 96 | @ResponseBody |
88 | 97 | public EntityView saveEntityView(@RequestBody EntityView entityView) throws ThingsboardException { |
... | ... | @@ -256,21 +265,22 @@ public class EntityViewController extends BaseController { |
256 | 265 | } |
257 | 266 | |
258 | 267 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
259 | - @RequestMapping(value = "/customer/{customerId}/entityViews", params = {"limit"}, method = RequestMethod.GET) | |
268 | + @RequestMapping(value = "/customer/{customerId}/entityViews", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
260 | 269 | @ResponseBody |
261 | - public TextPageData<EntityView> getCustomerEntityViews( | |
270 | + public PageData<EntityView> getCustomerEntityViews( | |
262 | 271 | @PathVariable("customerId") String strCustomerId, |
263 | - @RequestParam int limit, | |
272 | + @RequestParam int pageSize, | |
273 | + @RequestParam int page, | |
264 | 274 | @RequestParam(required = false) String type, |
265 | 275 | @RequestParam(required = false) String textSearch, |
266 | - @RequestParam(required = false) String idOffset, | |
267 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
276 | + @RequestParam(required = false) String sortProperty, | |
277 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
268 | 278 | checkParameter("customerId", strCustomerId); |
269 | 279 | try { |
270 | 280 | TenantId tenantId = getCurrentUser().getTenantId(); |
271 | 281 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
272 | 282 | checkCustomerId(customerId, Operation.READ); |
273 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
283 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
274 | 284 | if (type != null && type.trim().length() > 0) { |
275 | 285 | return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId, customerId, pageLink, type)); |
276 | 286 | } else { |
... | ... | @@ -281,18 +291,46 @@ public class EntityViewController extends BaseController { |
281 | 291 | } |
282 | 292 | } |
283 | 293 | |
294 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
295 | + @RequestMapping(value = "/customer/{customerId}/entityViewInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
296 | + @ResponseBody | |
297 | + public PageData<EntityViewInfo> getCustomerEntityViewInfos( | |
298 | + @PathVariable("customerId") String strCustomerId, | |
299 | + @RequestParam int pageSize, | |
300 | + @RequestParam int page, | |
301 | + @RequestParam(required = false) String type, | |
302 | + @RequestParam(required = false) String textSearch, | |
303 | + @RequestParam(required = false) String sortProperty, | |
304 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
305 | + checkParameter("customerId", strCustomerId); | |
306 | + try { | |
307 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
308 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
309 | + checkCustomerId(customerId, Operation.READ); | |
310 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
311 | + if (type != null && type.trim().length() > 0) { | |
312 | + return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); | |
313 | + } else { | |
314 | + return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
315 | + } | |
316 | + } catch (Exception e) { | |
317 | + throw handleException(e); | |
318 | + } | |
319 | + } | |
320 | + | |
284 | 321 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
285 | - @RequestMapping(value = "/tenant/entityViews", params = {"limit"}, method = RequestMethod.GET) | |
322 | + @RequestMapping(value = "/tenant/entityViews", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
286 | 323 | @ResponseBody |
287 | - public TextPageData<EntityView> getTenantEntityViews( | |
288 | - @RequestParam int limit, | |
324 | + public PageData<EntityView> getTenantEntityViews( | |
325 | + @RequestParam int pageSize, | |
326 | + @RequestParam int page, | |
289 | 327 | @RequestParam(required = false) String type, |
290 | 328 | @RequestParam(required = false) String textSearch, |
291 | - @RequestParam(required = false) String idOffset, | |
292 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
329 | + @RequestParam(required = false) String sortProperty, | |
330 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
293 | 331 | try { |
294 | 332 | TenantId tenantId = getCurrentUser().getTenantId(); |
295 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
333 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
296 | 334 | |
297 | 335 | if (type != null && type.trim().length() > 0) { |
298 | 336 | return checkNotNull(entityViewService.findEntityViewByTenantIdAndType(tenantId, pageLink, type)); |
... | ... | @@ -304,6 +342,29 @@ public class EntityViewController extends BaseController { |
304 | 342 | } |
305 | 343 | } |
306 | 344 | |
345 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
346 | + @RequestMapping(value = "/tenant/entityViewInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
347 | + @ResponseBody | |
348 | + public PageData<EntityViewInfo> getTenantEntityViewInfos( | |
349 | + @RequestParam int pageSize, | |
350 | + @RequestParam int page, | |
351 | + @RequestParam(required = false) String type, | |
352 | + @RequestParam(required = false) String textSearch, | |
353 | + @RequestParam(required = false) String sortProperty, | |
354 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
355 | + try { | |
356 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
357 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
358 | + if (type != null && type.trim().length() > 0) { | |
359 | + return checkNotNull(entityViewService.findEntityViewInfosByTenantIdAndType(tenantId, type, pageLink)); | |
360 | + } else { | |
361 | + return checkNotNull(entityViewService.findEntityViewInfosByTenantId(tenantId, pageLink)); | |
362 | + } | |
363 | + } catch (Exception e) { | |
364 | + throw handleException(e); | |
365 | + } | |
366 | + } | |
367 | + | |
307 | 368 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
308 | 369 | @RequestMapping(value = "/entityViews", method = RequestMethod.POST) |
309 | 370 | @ResponseBody | ... | ... |
... | ... | @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; |
28 | 28 | import org.thingsboard.server.common.data.id.EntityId; |
29 | 29 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
30 | 30 | import org.thingsboard.server.common.data.id.TenantId; |
31 | -import org.thingsboard.server.common.data.page.TimePageData; | |
31 | +import org.thingsboard.server.common.data.page.PageData; | |
32 | 32 | import org.thingsboard.server.common.data.page.TimePageLink; |
33 | 33 | import org.thingsboard.server.dao.event.EventService; |
34 | 34 | import org.thingsboard.server.service.security.permission.Operation; |
... | ... | @@ -43,17 +43,18 @@ public class EventController extends BaseController { |
43 | 43 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
44 | 44 | @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET) |
45 | 45 | @ResponseBody |
46 | - public TimePageData<Event> getEvents( | |
46 | + public PageData<Event> getEvents( | |
47 | 47 | @PathVariable("entityType") String strEntityType, |
48 | 48 | @PathVariable("entityId") String strEntityId, |
49 | 49 | @PathVariable("eventType") String eventType, |
50 | 50 | @RequestParam("tenantId") String strTenantId, |
51 | - @RequestParam int limit, | |
51 | + @RequestParam int pageSize, | |
52 | + @RequestParam int page, | |
53 | + @RequestParam(required = false) String textSearch, | |
54 | + @RequestParam(required = false) String sortProperty, | |
55 | + @RequestParam(required = false) String sortOrder, | |
52 | 56 | @RequestParam(required = false) Long startTime, |
53 | - @RequestParam(required = false) Long endTime, | |
54 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
55 | - @RequestParam(required = false) String offset | |
56 | - ) throws ThingsboardException { | |
57 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | |
57 | 58 | checkParameter("EntityId", strEntityId); |
58 | 59 | checkParameter("EntityType", strEntityType); |
59 | 60 | try { |
... | ... | @@ -61,8 +62,7 @@ public class EventController extends BaseController { |
61 | 62 | |
62 | 63 | EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); |
63 | 64 | checkEntityId(entityId, Operation.READ); |
64 | - | |
65 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
65 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
66 | 66 | return checkNotNull(eventService.findEvents(tenantId, entityId, eventType, pageLink)); |
67 | 67 | } catch (Exception e) { |
68 | 68 | throw handleException(e); |
... | ... | @@ -72,16 +72,17 @@ public class EventController extends BaseController { |
72 | 72 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
73 | 73 | @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET) |
74 | 74 | @ResponseBody |
75 | - public TimePageData<Event> getEvents( | |
75 | + public PageData<Event> getEvents( | |
76 | 76 | @PathVariable("entityType") String strEntityType, |
77 | 77 | @PathVariable("entityId") String strEntityId, |
78 | 78 | @RequestParam("tenantId") String strTenantId, |
79 | - @RequestParam int limit, | |
79 | + @RequestParam int pageSize, | |
80 | + @RequestParam int page, | |
81 | + @RequestParam(required = false) String textSearch, | |
82 | + @RequestParam(required = false) String sortProperty, | |
83 | + @RequestParam(required = false) String sortOrder, | |
80 | 84 | @RequestParam(required = false) Long startTime, |
81 | - @RequestParam(required = false) Long endTime, | |
82 | - @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
83 | - @RequestParam(required = false) String offset | |
84 | - ) throws ThingsboardException { | |
85 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | |
85 | 86 | checkParameter("EntityId", strEntityId); |
86 | 87 | checkParameter("EntityType", strEntityType); |
87 | 88 | try { |
... | ... | @@ -90,7 +91,8 @@ public class EventController extends BaseController { |
90 | 91 | EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); |
91 | 92 | checkEntityId(entityId, Operation.READ); |
92 | 93 | |
93 | - TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
94 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | |
95 | + | |
94 | 96 | return checkNotNull(eventService.findEvents(tenantId, entityId, pageLink)); |
95 | 97 | } catch (Exception e) { |
96 | 98 | throw handleException(e); | ... | ... |
... | ... | @@ -45,8 +45,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; |
45 | 45 | import org.thingsboard.server.common.data.id.RuleChainId; |
46 | 46 | import org.thingsboard.server.common.data.id.RuleNodeId; |
47 | 47 | import org.thingsboard.server.common.data.id.TenantId; |
48 | -import org.thingsboard.server.common.data.page.TextPageData; | |
49 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
48 | +import org.thingsboard.server.common.data.page.PageData; | |
49 | +import org.thingsboard.server.common.data.page.PageLink; | |
50 | 50 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
51 | 51 | import org.thingsboard.server.common.data.rule.RuleChain; |
52 | 52 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
... | ... | @@ -220,16 +220,17 @@ public class RuleChainController extends BaseController { |
220 | 220 | } |
221 | 221 | |
222 | 222 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
223 | - @RequestMapping(value = "/ruleChains", params = {"limit"}, method = RequestMethod.GET) | |
223 | + @RequestMapping(value = "/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
224 | 224 | @ResponseBody |
225 | - public TextPageData<RuleChain> getRuleChains( | |
226 | - @RequestParam int limit, | |
225 | + public PageData<RuleChain> getRuleChains( | |
226 | + @RequestParam int pageSize, | |
227 | + @RequestParam int page, | |
227 | 228 | @RequestParam(required = false) String textSearch, |
228 | - @RequestParam(required = false) String idOffset, | |
229 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
229 | + @RequestParam(required = false) String sortProperty, | |
230 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
230 | 231 | try { |
231 | 232 | TenantId tenantId = getCurrentUser().getTenantId(); |
232 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
233 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
233 | 234 | return checkNotNull(ruleChainService.findTenantRuleChains(tenantId, pageLink)); |
234 | 235 | } catch (Exception e) { |
235 | 236 | throw handleException(e); | ... | ... |
... | ... | @@ -30,8 +30,8 @@ import org.springframework.web.bind.annotation.RestController; |
30 | 30 | import org.thingsboard.server.common.data.Tenant; |
31 | 31 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
32 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
33 | -import org.thingsboard.server.common.data.page.TextPageData; | |
34 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
33 | +import org.thingsboard.server.common.data.page.PageData; | |
34 | +import org.thingsboard.server.common.data.page.PageLink; | |
35 | 35 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
36 | 36 | import org.thingsboard.server.dao.tenant.TenantService; |
37 | 37 | import org.thingsboard.server.service.install.InstallScripts; |
... | ... | @@ -102,14 +102,15 @@ public class TenantController extends BaseController { |
102 | 102 | } |
103 | 103 | |
104 | 104 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
105 | - @RequestMapping(value = "/tenants", params = {"limit"}, method = RequestMethod.GET) | |
105 | + @RequestMapping(value = "/tenants", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
106 | 106 | @ResponseBody |
107 | - public TextPageData<Tenant> getTenants(@RequestParam int limit, | |
108 | - @RequestParam(required = false) String textSearch, | |
109 | - @RequestParam(required = false) String idOffset, | |
110 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
107 | + public PageData<Tenant> getTenants(@RequestParam int pageSize, | |
108 | + @RequestParam int page, | |
109 | + @RequestParam(required = false) String textSearch, | |
110 | + @RequestParam(required = false) String sortProperty, | |
111 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
111 | 112 | try { |
112 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
113 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
113 | 114 | return checkNotNull(tenantService.findTenants(pageLink)); |
114 | 115 | } catch (Exception e) { |
115 | 116 | throw handleException(e); | ... | ... |
... | ... | @@ -40,8 +40,8 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; |
40 | 40 | import org.thingsboard.server.common.data.id.CustomerId; |
41 | 41 | import org.thingsboard.server.common.data.id.TenantId; |
42 | 42 | import org.thingsboard.server.common.data.id.UserId; |
43 | -import org.thingsboard.server.common.data.page.TextPageData; | |
44 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
43 | +import org.thingsboard.server.common.data.page.PageData; | |
44 | +import org.thingsboard.server.common.data.page.PageLink; | |
45 | 45 | import org.thingsboard.server.common.data.security.Authority; |
46 | 46 | import org.thingsboard.server.common.data.security.UserCredentials; |
47 | 47 | import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; |
... | ... | @@ -247,18 +247,19 @@ public class UserController extends BaseController { |
247 | 247 | } |
248 | 248 | |
249 | 249 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
250 | - @RequestMapping(value = "/tenant/{tenantId}/users", params = { "limit" }, method = RequestMethod.GET) | |
250 | + @RequestMapping(value = "/tenant/{tenantId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
251 | 251 | @ResponseBody |
252 | - public TextPageData<User> getTenantAdmins( | |
252 | + public PageData<User> getTenantAdmins( | |
253 | 253 | @PathVariable("tenantId") String strTenantId, |
254 | - @RequestParam int limit, | |
254 | + @RequestParam int pageSize, | |
255 | + @RequestParam int page, | |
255 | 256 | @RequestParam(required = false) String textSearch, |
256 | - @RequestParam(required = false) String idOffset, | |
257 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
257 | + @RequestParam(required = false) String sortProperty, | |
258 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
258 | 259 | checkParameter("tenantId", strTenantId); |
259 | 260 | try { |
260 | 261 | TenantId tenantId = new TenantId(toUUID(strTenantId)); |
261 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
262 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
262 | 263 | return checkNotNull(userService.findTenantAdmins(tenantId, pageLink)); |
263 | 264 | } catch (Exception e) { |
264 | 265 | throw handleException(e); |
... | ... | @@ -266,19 +267,20 @@ public class UserController extends BaseController { |
266 | 267 | } |
267 | 268 | |
268 | 269 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
269 | - @RequestMapping(value = "/customer/{customerId}/users", params = { "limit" }, method = RequestMethod.GET) | |
270 | + @RequestMapping(value = "/customer/{customerId}/users", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
270 | 271 | @ResponseBody |
271 | - public TextPageData<User> getCustomerUsers( | |
272 | + public PageData<User> getCustomerUsers( | |
272 | 273 | @PathVariable("customerId") String strCustomerId, |
273 | - @RequestParam int limit, | |
274 | + @RequestParam int pageSize, | |
275 | + @RequestParam int page, | |
274 | 276 | @RequestParam(required = false) String textSearch, |
275 | - @RequestParam(required = false) String idOffset, | |
276 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
277 | + @RequestParam(required = false) String sortProperty, | |
278 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
277 | 279 | checkParameter("customerId", strCustomerId); |
278 | 280 | try { |
279 | 281 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
280 | 282 | checkCustomerId(customerId, Operation.READ); |
281 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
283 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
282 | 284 | TenantId tenantId = getCurrentUser().getTenantId(); |
283 | 285 | return checkNotNull(userService.findCustomerUsers(tenantId, customerId, pageLink)); |
284 | 286 | } catch (Exception e) { | ... | ... |
... | ... | @@ -28,8 +28,8 @@ import org.springframework.web.bind.annotation.RestController; |
28 | 28 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
29 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | 30 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
31 | -import org.thingsboard.server.common.data.page.TextPageData; | |
32 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
31 | +import org.thingsboard.server.common.data.page.PageData; | |
32 | +import org.thingsboard.server.common.data.page.PageLink; | |
33 | 33 | import org.thingsboard.server.common.data.security.Authority; |
34 | 34 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
35 | 35 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -92,15 +92,16 @@ public class WidgetsBundleController extends BaseController { |
92 | 92 | } |
93 | 93 | |
94 | 94 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
95 | - @RequestMapping(value = "/widgetsBundles", params = { "limit" }, method = RequestMethod.GET) | |
95 | + @RequestMapping(value = "/widgetsBundles", params = {"pageSize", "page"}, method = RequestMethod.GET) | |
96 | 96 | @ResponseBody |
97 | - public TextPageData<WidgetsBundle> getWidgetsBundles( | |
98 | - @RequestParam int limit, | |
97 | + public PageData<WidgetsBundle> getWidgetsBundles( | |
98 | + @RequestParam int pageSize, | |
99 | + @RequestParam int page, | |
99 | 100 | @RequestParam(required = false) String textSearch, |
100 | - @RequestParam(required = false) String idOffset, | |
101 | - @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
101 | + @RequestParam(required = false) String sortProperty, | |
102 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | |
102 | 103 | try { |
103 | - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
104 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | |
104 | 105 | if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { |
105 | 106 | return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), pageLink)); |
106 | 107 | } else { | ... | ... |
... | ... | @@ -22,8 +22,8 @@ import org.springframework.stereotype.Service; |
22 | 22 | import org.thingsboard.server.common.data.SearchTextBased; |
23 | 23 | import org.thingsboard.server.common.data.Tenant; |
24 | 24 | import org.thingsboard.server.common.data.id.UUIDBased; |
25 | -import org.thingsboard.server.common.data.page.TextPageData; | |
26 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
25 | +import org.thingsboard.server.common.data.page.PageData; | |
26 | +import org.thingsboard.server.common.data.page.PageLink; | |
27 | 27 | import org.thingsboard.server.common.data.rule.RuleChain; |
28 | 28 | import org.thingsboard.server.dao.rule.RuleChainService; |
29 | 29 | import org.thingsboard.server.dao.tenant.TenantService; |
... | ... | @@ -59,7 +59,7 @@ public class DefaultDataUpdateService implements DataUpdateService { |
59 | 59 | new PaginatedUpdater<String, Tenant>() { |
60 | 60 | |
61 | 61 | @Override |
62 | - protected TextPageData<Tenant> findEntities(String region, TextPageLink pageLink) { | |
62 | + protected PageData<Tenant> findEntities(String region, PageLink pageLink) { | |
63 | 63 | return tenantService.findTenants(pageLink); |
64 | 64 | } |
65 | 65 | ... | ... |
... | ... | @@ -17,29 +17,29 @@ package org.thingsboard.server.service.install.update; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.SearchTextBased; |
19 | 19 | import org.thingsboard.server.common.data.id.UUIDBased; |
20 | -import org.thingsboard.server.common.data.page.TextPageData; | |
21 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
20 | +import org.thingsboard.server.common.data.page.PageData; | |
21 | +import org.thingsboard.server.common.data.page.PageLink; | |
22 | 22 | |
23 | 23 | public abstract class PaginatedUpdater<I, D extends SearchTextBased<? extends UUIDBased>> { |
24 | 24 | |
25 | 25 | private static final int DEFAULT_LIMIT = 100; |
26 | 26 | |
27 | 27 | public void updateEntities(I id) { |
28 | - TextPageLink pageLink = new TextPageLink(DEFAULT_LIMIT); | |
28 | + PageLink pageLink = new PageLink(DEFAULT_LIMIT); | |
29 | 29 | boolean hasNext = true; |
30 | 30 | while (hasNext) { |
31 | - TextPageData<D> entities = findEntities(id, pageLink); | |
31 | + PageData<D> entities = findEntities(id, pageLink); | |
32 | 32 | for (D entity : entities.getData()) { |
33 | 33 | updateEntity(entity); |
34 | 34 | } |
35 | 35 | hasNext = entities.hasNext(); |
36 | 36 | if (hasNext) { |
37 | - pageLink = entities.getNextPageLink(); | |
37 | + pageLink = pageLink.nextPageLink(); | |
38 | 38 | } |
39 | 39 | } |
40 | 40 | } |
41 | 41 | |
42 | - protected abstract TextPageData<D> findEntities(I id, TextPageLink pageLink); | |
42 | + protected abstract PageData<D> findEntities(I id, PageLink pageLink); | |
43 | 43 | |
44 | 44 | protected abstract void updateEntity(D entity); |
45 | 45 | ... | ... |
... | ... | @@ -112,8 +112,11 @@ public class DefaultMailService implements MailService { |
112 | 112 | } |
113 | 113 | } |
114 | 114 | javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", enableTls); |
115 | - if (enableTls && jsonConfig.has("tlsVersion") && StringUtils.isNoneEmpty(jsonConfig.get("tlsVersion").asText())) { | |
116 | - javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", jsonConfig.get("tlsVersion").asText()); | |
115 | + if (enableTls && jsonConfig.has("tlsVersion") && !jsonConfig.get("tlsVersion").isNull()) { | |
116 | + String tlsVersion = jsonConfig.get("tlsVersion").asText(); | |
117 | + if (StringUtils.isNoneEmpty(tlsVersion)) { | |
118 | + javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", tlsVersion); | |
119 | + } | |
117 | 120 | } |
118 | 121 | return javaMailProperties; |
119 | 122 | } | ... | ... |
... | ... | @@ -39,13 +39,13 @@ import org.thingsboard.server.common.data.Tenant; |
39 | 39 | import org.thingsboard.server.common.data.id.DeviceId; |
40 | 40 | import org.thingsboard.server.common.data.id.TenantId; |
41 | 41 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
42 | +import org.thingsboard.server.common.data.page.PageData; | |
43 | +import org.thingsboard.server.common.data.page.PageLink; | |
42 | 44 | import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
43 | 45 | import org.thingsboard.server.common.data.kv.BooleanDataEntry; |
44 | 46 | import org.thingsboard.server.common.data.kv.KvEntry; |
45 | 47 | import org.thingsboard.server.common.data.kv.LongDataEntry; |
46 | 48 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
47 | -import org.thingsboard.server.common.data.page.TextPageData; | |
48 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
49 | 49 | import org.thingsboard.server.common.msg.TbMsg; |
50 | 50 | import org.thingsboard.server.common.msg.TbMsgDataType; |
51 | 51 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
... | ... | @@ -227,13 +227,13 @@ public class DefaultDeviceStateService implements DeviceStateService { |
227 | 227 | |
228 | 228 | private void onClusterUpdateSync() { |
229 | 229 | clusterUpdatePending = false; |
230 | - List<Tenant> tenants = tenantService.findTenants(new TextPageLink(Integer.MAX_VALUE)).getData(); | |
230 | + List<Tenant> tenants = tenantService.findTenants(new PageLink(Integer.MAX_VALUE)).getData(); | |
231 | 231 | for (Tenant tenant : tenants) { |
232 | 232 | List<ListenableFuture<DeviceStateData>> fetchFutures = new ArrayList<>(); |
233 | - TextPageLink pageLink = new TextPageLink(initFetchPackSize); | |
233 | + PageLink pageLink = new PageLink(initFetchPackSize); | |
234 | 234 | while (pageLink != null) { |
235 | - TextPageData<Device> page = deviceService.findDevicesByTenantId(tenant.getId(), pageLink); | |
236 | - pageLink = page.getNextPageLink(); | |
235 | + PageData<Device> page = deviceService.findDevicesByTenantId(tenant.getId(), pageLink); | |
236 | + pageLink = page.hasNext() ? pageLink.nextPageLink() : null; | |
237 | 237 | for (Device device : page.getData()) { |
238 | 238 | if (!routingService.resolveById(device.getId()).isPresent()) { |
239 | 239 | if (!deviceStates.containsKey(device.getId())) { |
... | ... | @@ -260,13 +260,13 @@ public class DefaultDeviceStateService implements DeviceStateService { |
260 | 260 | |
261 | 261 | private void initStateFromDB() { |
262 | 262 | try { |
263 | - List<Tenant> tenants = tenantService.findTenants(new TextPageLink(Integer.MAX_VALUE)).getData(); | |
263 | + List<Tenant> tenants = tenantService.findTenants(new PageLink(Integer.MAX_VALUE)).getData(); | |
264 | 264 | for (Tenant tenant : tenants) { |
265 | 265 | List<ListenableFuture<DeviceStateData>> fetchFutures = new ArrayList<>(); |
266 | - TextPageLink pageLink = new TextPageLink(initFetchPackSize); | |
266 | + PageLink pageLink = new PageLink(initFetchPackSize); | |
267 | 267 | while (pageLink != null) { |
268 | - TextPageData<Device> page = deviceService.findDevicesByTenantId(tenant.getId(), pageLink); | |
269 | - pageLink = page.getNextPageLink(); | |
268 | + PageData<Device> page = deviceService.findDevicesByTenantId(tenant.getId(), pageLink); | |
269 | + pageLink = page.hasNext() ? pageLink.nextPageLink() : null; | |
270 | 270 | for (Device device : page.getData()) { |
271 | 271 | if (!routingService.resolveById(device.getId()).isPresent()) { |
272 | 272 | fetchFutures.add(fetchDeviceState(device)); | ... | ... |
... | ... | @@ -119,8 +119,6 @@ dashboard: |
119 | 119 | |
120 | 120 | database: |
121 | 121 | ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records |
122 | - entities: | |
123 | - type: "${DATABASE_ENTITIES_TYPE:sql}" # cassandra OR sql | |
124 | 122 | ts: |
125 | 123 | type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale) |
126 | 124 | |
... | ... | @@ -366,6 +364,7 @@ spring.resources.chain: |
366 | 364 | enabled: "true" |
367 | 365 | |
368 | 366 | spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" |
367 | +spring.jpa.properties.hibernate.order_by.default_null_ordering: "last" | |
369 | 368 | |
370 | 369 | # SQL DAO Configuration |
371 | 370 | spring: | ... | ... |
... | ... | @@ -65,7 +65,8 @@ import org.thingsboard.server.common.data.Tenant; |
65 | 65 | import org.thingsboard.server.common.data.User; |
66 | 66 | import org.thingsboard.server.common.data.id.TenantId; |
67 | 67 | import org.thingsboard.server.common.data.id.UUIDBased; |
68 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
68 | +import org.thingsboard.server.common.data.page.PageLink; | |
69 | +import org.thingsboard.server.common.data.page.SortOrder; | |
69 | 70 | import org.thingsboard.server.common.data.page.TimePageLink; |
70 | 71 | import org.thingsboard.server.common.data.security.Authority; |
71 | 72 | import org.thingsboard.server.config.ThingsboardSecurityConfiguration; |
... | ... | @@ -314,22 +315,20 @@ public abstract class AbstractControllerTest { |
314 | 315 | } |
315 | 316 | |
316 | 317 | protected <T> T doGetTypedWithPageLink(String urlTemplate, TypeReference<T> responseType, |
317 | - TextPageLink pageLink, | |
318 | + PageLink pageLink, | |
318 | 319 | Object... urlVariables) throws Exception { |
319 | 320 | List<Object> pageLinkVariables = new ArrayList<>(); |
320 | - urlTemplate += "limit={limit}"; | |
321 | - pageLinkVariables.add(pageLink.getLimit()); | |
321 | + urlTemplate += "pageSize={pageSize}&page={page}"; | |
322 | + pageLinkVariables.add(pageLink.getPageSize()); | |
323 | + pageLinkVariables.add(pageLink.getPage()); | |
322 | 324 | if (StringUtils.isNotEmpty(pageLink.getTextSearch())) { |
323 | 325 | urlTemplate += "&textSearch={textSearch}"; |
324 | 326 | pageLinkVariables.add(pageLink.getTextSearch()); |
325 | 327 | } |
326 | - if (pageLink.getIdOffset() != null) { | |
327 | - urlTemplate += "&idOffset={idOffset}"; | |
328 | - pageLinkVariables.add(pageLink.getIdOffset().toString()); | |
329 | - } | |
330 | - if (StringUtils.isNotEmpty(pageLink.getTextOffset())) { | |
331 | - urlTemplate += "&textOffset={textOffset}"; | |
332 | - pageLinkVariables.add(pageLink.getTextOffset()); | |
328 | + if (pageLink.getSortOrder() != null) { | |
329 | + urlTemplate += "&sortProperty={sortProperty}&sortOrder={sortOrder}"; | |
330 | + pageLinkVariables.add(pageLink.getSortOrder().getProperty()); | |
331 | + pageLinkVariables.add(pageLink.getSortOrder().getDirection().name()); | |
333 | 332 | } |
334 | 333 | |
335 | 334 | Object[] vars = new Object[urlVariables.length + pageLinkVariables.size()]; |
... | ... | @@ -343,8 +342,9 @@ public abstract class AbstractControllerTest { |
343 | 342 | TimePageLink pageLink, |
344 | 343 | Object... urlVariables) throws Exception { |
345 | 344 | List<Object> pageLinkVariables = new ArrayList<>(); |
346 | - urlTemplate += "limit={limit}"; | |
347 | - pageLinkVariables.add(pageLink.getLimit()); | |
345 | + urlTemplate += "pageSize={pageSize}&page={page}"; | |
346 | + pageLinkVariables.add(pageLink.getPageSize()); | |
347 | + pageLinkVariables.add(pageLink.getPage()); | |
348 | 348 | if (pageLink.getStartTime() != null) { |
349 | 349 | urlTemplate += "&startTime={startTime}"; |
350 | 350 | pageLinkVariables.add(pageLink.getStartTime()); |
... | ... | @@ -353,13 +353,14 @@ public abstract class AbstractControllerTest { |
353 | 353 | urlTemplate += "&endTime={endTime}"; |
354 | 354 | pageLinkVariables.add(pageLink.getEndTime()); |
355 | 355 | } |
356 | - if (pageLink.getIdOffset() != null) { | |
357 | - urlTemplate += "&offset={offset}"; | |
358 | - pageLinkVariables.add(pageLink.getIdOffset().toString()); | |
356 | + if (StringUtils.isNotEmpty(pageLink.getTextSearch())) { | |
357 | + urlTemplate += "&textSearch={textSearch}"; | |
358 | + pageLinkVariables.add(pageLink.getTextSearch()); | |
359 | 359 | } |
360 | - if (pageLink.isAscOrder()) { | |
361 | - urlTemplate += "&ascOrder={ascOrder}"; | |
362 | - pageLinkVariables.add(pageLink.isAscOrder()); | |
360 | + if (pageLink.getSortOrder() != null) { | |
361 | + urlTemplate += "&sortProperty={sortProperty}&sortOrder={sortOrder}"; | |
362 | + pageLinkVariables.add(pageLink.getSortOrder().getProperty()); | |
363 | + pageLinkVariables.add(pageLink.getSortOrder().getDirection().name()); | |
363 | 364 | } |
364 | 365 | Object[] vars = new Object[urlVariables.length + pageLinkVariables.size()]; |
365 | 366 | System.arraycopy(urlVariables, 0, vars, 0, urlVariables.length); | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.Event; |
23 | 23 | import org.thingsboard.server.common.data.id.EntityId; |
24 | 24 | import org.thingsboard.server.common.data.id.RuleChainId; |
25 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
26 | -import org.thingsboard.server.common.data.page.TimePageData; | |
26 | +import org.thingsboard.server.common.data.page.PageData; | |
27 | 27 | import org.thingsboard.server.common.data.page.TimePageLink; |
28 | 28 | import org.thingsboard.server.common.data.rule.RuleChain; |
29 | 29 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
... | ... | @@ -56,10 +56,10 @@ public class AbstractRuleEngineControllerTest extends AbstractControllerTest { |
56 | 56 | return doGet("/api/ruleChain/metadata/" + ruleChainId.getId().toString(), RuleChainMetaData.class); |
57 | 57 | } |
58 | 58 | |
59 | - protected TimePageData<Event> getDebugEvents(TenantId tenantId, EntityId entityId, int limit) throws Exception { | |
59 | + protected PageData<Event> getDebugEvents(TenantId tenantId, EntityId entityId, int limit) throws Exception { | |
60 | 60 | TimePageLink pageLink = new TimePageLink(limit); |
61 | 61 | return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&", |
62 | - new TypeReference<TimePageData<Event>>() { | |
62 | + new TypeReference<PageData<Event>>() { | |
63 | 63 | }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG_RULE_NODE, tenantId.getId()); |
64 | 64 | } |
65 | 65 | ... | ... |
... | ... | @@ -28,8 +28,8 @@ import org.thingsboard.server.common.data.Tenant; |
28 | 28 | import org.thingsboard.server.common.data.User; |
29 | 29 | import org.thingsboard.server.common.data.asset.Asset; |
30 | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
31 | -import org.thingsboard.server.common.data.page.TextPageData; | |
32 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
31 | +import org.thingsboard.server.common.data.page.PageData; | |
32 | +import org.thingsboard.server.common.data.page.PageLink; | |
33 | 33 | import org.thingsboard.server.common.data.security.Authority; |
34 | 34 | import org.thingsboard.server.dao.model.ModelConstants; |
35 | 35 | |
... | ... | @@ -258,14 +258,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
258 | 258 | assets.add(doPost("/api/asset", asset, Asset.class)); |
259 | 259 | } |
260 | 260 | List<Asset> loadedAssets = new ArrayList<>(); |
261 | - TextPageLink pageLink = new TextPageLink(23); | |
262 | - TextPageData<Asset> pageData = null; | |
261 | + PageLink pageLink = new PageLink(23); | |
262 | + PageData<Asset> pageData = null; | |
263 | 263 | do { |
264 | 264 | pageData = doGetTypedWithPageLink("/api/tenant/assets?", |
265 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
265 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
266 | 266 | loadedAssets.addAll(pageData.getData()); |
267 | 267 | if (pageData.hasNext()) { |
268 | - pageLink = pageData.getNextPageLink(); | |
268 | + pageLink = pageLink.nextPageLink(); | |
269 | 269 | } |
270 | 270 | } while (pageData.hasNext()); |
271 | 271 | |
... | ... | @@ -301,14 +301,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
301 | 301 | } |
302 | 302 | |
303 | 303 | List<Asset> loadedAssetsTitle1 = new ArrayList<>(); |
304 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
305 | - TextPageData<Asset> pageData = null; | |
304 | + PageLink pageLink = new PageLink(15, 0, title1); | |
305 | + PageData<Asset> pageData = null; | |
306 | 306 | do { |
307 | 307 | pageData = doGetTypedWithPageLink("/api/tenant/assets?", |
308 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
308 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
309 | 309 | loadedAssetsTitle1.addAll(pageData.getData()); |
310 | 310 | if (pageData.hasNext()) { |
311 | - pageLink = pageData.getNextPageLink(); | |
311 | + pageLink = pageLink.nextPageLink(); | |
312 | 312 | } |
313 | 313 | } while (pageData.hasNext()); |
314 | 314 | |
... | ... | @@ -318,13 +318,13 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
318 | 318 | Assert.assertEquals(assetsTitle1, loadedAssetsTitle1); |
319 | 319 | |
320 | 320 | List<Asset> loadedAssetsTitle2 = new ArrayList<>(); |
321 | - pageLink = new TextPageLink(4, title2); | |
321 | + pageLink = new PageLink(4, 0, title2); | |
322 | 322 | do { |
323 | 323 | pageData = doGetTypedWithPageLink("/api/tenant/assets?", |
324 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
324 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
325 | 325 | loadedAssetsTitle2.addAll(pageData.getData()); |
326 | 326 | if (pageData.hasNext()) { |
327 | - pageLink = pageData.getNextPageLink(); | |
327 | + pageLink = pageLink.nextPageLink(); | |
328 | 328 | } |
329 | 329 | } while (pageData.hasNext()); |
330 | 330 | |
... | ... | @@ -338,9 +338,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
338 | 338 | .andExpect(status().isOk()); |
339 | 339 | } |
340 | 340 | |
341 | - pageLink = new TextPageLink(4, title1); | |
341 | + pageLink = new PageLink(4, 0, title1); | |
342 | 342 | pageData = doGetTypedWithPageLink("/api/tenant/assets?", |
343 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
343 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
344 | 344 | Assert.assertFalse(pageData.hasNext()); |
345 | 345 | Assert.assertEquals(0, pageData.getData().size()); |
346 | 346 | |
... | ... | @@ -349,9 +349,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
349 | 349 | .andExpect(status().isOk()); |
350 | 350 | } |
351 | 351 | |
352 | - pageLink = new TextPageLink(4, title2); | |
352 | + pageLink = new PageLink(4, 0, title2); | |
353 | 353 | pageData = doGetTypedWithPageLink("/api/tenant/assets?", |
354 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
354 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
355 | 355 | Assert.assertFalse(pageData.hasNext()); |
356 | 356 | Assert.assertEquals(0, pageData.getData().size()); |
357 | 357 | } |
... | ... | @@ -384,14 +384,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
384 | 384 | } |
385 | 385 | |
386 | 386 | List<Asset> loadedAssetsType1 = new ArrayList<>(); |
387 | - TextPageLink pageLink = new TextPageLink(15); | |
388 | - TextPageData<Asset> pageData = null; | |
387 | + PageLink pageLink = new PageLink(15); | |
388 | + PageData<Asset> pageData = null; | |
389 | 389 | do { |
390 | 390 | pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", |
391 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type1); | |
391 | + new TypeReference<PageData<Asset>>(){}, pageLink, type1); | |
392 | 392 | loadedAssetsType1.addAll(pageData.getData()); |
393 | 393 | if (pageData.hasNext()) { |
394 | - pageLink = pageData.getNextPageLink(); | |
394 | + pageLink = pageLink.nextPageLink(); | |
395 | 395 | } |
396 | 396 | } while (pageData.hasNext()); |
397 | 397 | |
... | ... | @@ -401,13 +401,13 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
401 | 401 | Assert.assertEquals(assetsType1, loadedAssetsType1); |
402 | 402 | |
403 | 403 | List<Asset> loadedAssetsType2 = new ArrayList<>(); |
404 | - pageLink = new TextPageLink(4); | |
404 | + pageLink = new PageLink(4); | |
405 | 405 | do { |
406 | 406 | pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", |
407 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type2); | |
407 | + new TypeReference<PageData<Asset>>(){}, pageLink, type2); | |
408 | 408 | loadedAssetsType2.addAll(pageData.getData()); |
409 | 409 | if (pageData.hasNext()) { |
410 | - pageLink = pageData.getNextPageLink(); | |
410 | + pageLink = pageLink.nextPageLink(); | |
411 | 411 | } |
412 | 412 | } while (pageData.hasNext()); |
413 | 413 | |
... | ... | @@ -421,9 +421,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
421 | 421 | .andExpect(status().isOk()); |
422 | 422 | } |
423 | 423 | |
424 | - pageLink = new TextPageLink(4); | |
424 | + pageLink = new PageLink(4); | |
425 | 425 | pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", |
426 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type1); | |
426 | + new TypeReference<PageData<Asset>>(){}, pageLink, type1); | |
427 | 427 | Assert.assertFalse(pageData.hasNext()); |
428 | 428 | Assert.assertEquals(0, pageData.getData().size()); |
429 | 429 | |
... | ... | @@ -432,9 +432,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
432 | 432 | .andExpect(status().isOk()); |
433 | 433 | } |
434 | 434 | |
435 | - pageLink = new TextPageLink(4); | |
435 | + pageLink = new PageLink(4); | |
436 | 436 | pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", |
437 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type2); | |
437 | + new TypeReference<PageData<Asset>>(){}, pageLink, type2); | |
438 | 438 | Assert.assertFalse(pageData.hasNext()); |
439 | 439 | Assert.assertEquals(0, pageData.getData().size()); |
440 | 440 | } |
... | ... | @@ -457,14 +457,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
457 | 457 | } |
458 | 458 | |
459 | 459 | List<Asset> loadedAssets = new ArrayList<>(); |
460 | - TextPageLink pageLink = new TextPageLink(23); | |
461 | - TextPageData<Asset> pageData = null; | |
460 | + PageLink pageLink = new PageLink(23); | |
461 | + PageData<Asset> pageData = null; | |
462 | 462 | do { |
463 | 463 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", |
464 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
464 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
465 | 465 | loadedAssets.addAll(pageData.getData()); |
466 | 466 | if (pageData.hasNext()) { |
467 | - pageLink = pageData.getNextPageLink(); | |
467 | + pageLink = pageLink.nextPageLink(); | |
468 | 468 | } |
469 | 469 | } while (pageData.hasNext()); |
470 | 470 | |
... | ... | @@ -509,14 +509,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
509 | 509 | } |
510 | 510 | |
511 | 511 | List<Asset> loadedAssetsTitle1 = new ArrayList<>(); |
512 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
513 | - TextPageData<Asset> pageData = null; | |
512 | + PageLink pageLink = new PageLink(15, 0, title1); | |
513 | + PageData<Asset> pageData = null; | |
514 | 514 | do { |
515 | 515 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", |
516 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
516 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
517 | 517 | loadedAssetsTitle1.addAll(pageData.getData()); |
518 | 518 | if (pageData.hasNext()) { |
519 | - pageLink = pageData.getNextPageLink(); | |
519 | + pageLink = pageLink.nextPageLink(); | |
520 | 520 | } |
521 | 521 | } while (pageData.hasNext()); |
522 | 522 | |
... | ... | @@ -526,13 +526,13 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
526 | 526 | Assert.assertEquals(assetsTitle1, loadedAssetsTitle1); |
527 | 527 | |
528 | 528 | List<Asset> loadedAssetsTitle2 = new ArrayList<>(); |
529 | - pageLink = new TextPageLink(4, title2); | |
529 | + pageLink = new PageLink(4, 0, title2); | |
530 | 530 | do { |
531 | 531 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", |
532 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
532 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
533 | 533 | loadedAssetsTitle2.addAll(pageData.getData()); |
534 | 534 | if (pageData.hasNext()) { |
535 | - pageLink = pageData.getNextPageLink(); | |
535 | + pageLink = pageLink.nextPageLink(); | |
536 | 536 | } |
537 | 537 | } while (pageData.hasNext()); |
538 | 538 | |
... | ... | @@ -546,9 +546,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
546 | 546 | .andExpect(status().isOk()); |
547 | 547 | } |
548 | 548 | |
549 | - pageLink = new TextPageLink(4, title1); | |
549 | + pageLink = new PageLink(4, 0, title1); | |
550 | 550 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", |
551 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
551 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
552 | 552 | Assert.assertFalse(pageData.hasNext()); |
553 | 553 | Assert.assertEquals(0, pageData.getData().size()); |
554 | 554 | |
... | ... | @@ -557,9 +557,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
557 | 557 | .andExpect(status().isOk()); |
558 | 558 | } |
559 | 559 | |
560 | - pageLink = new TextPageLink(4, title2); | |
560 | + pageLink = new PageLink(4, 0, title2); | |
561 | 561 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", |
562 | - new TypeReference<TextPageData<Asset>>(){}, pageLink); | |
562 | + new TypeReference<PageData<Asset>>(){}, pageLink); | |
563 | 563 | Assert.assertFalse(pageData.hasNext()); |
564 | 564 | Assert.assertEquals(0, pageData.getData().size()); |
565 | 565 | } |
... | ... | @@ -601,14 +601,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
601 | 601 | } |
602 | 602 | |
603 | 603 | List<Asset> loadedAssetsType1 = new ArrayList<>(); |
604 | - TextPageLink pageLink = new TextPageLink(15); | |
605 | - TextPageData<Asset> pageData = null; | |
604 | + PageLink pageLink = new PageLink(15); | |
605 | + PageData<Asset> pageData = null; | |
606 | 606 | do { |
607 | 607 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", |
608 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type1); | |
608 | + new TypeReference<PageData<Asset>>(){}, pageLink, type1); | |
609 | 609 | loadedAssetsType1.addAll(pageData.getData()); |
610 | 610 | if (pageData.hasNext()) { |
611 | - pageLink = pageData.getNextPageLink(); | |
611 | + pageLink = pageLink.nextPageLink(); | |
612 | 612 | } |
613 | 613 | } while (pageData.hasNext()); |
614 | 614 | |
... | ... | @@ -618,13 +618,13 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
618 | 618 | Assert.assertEquals(assetsType1, loadedAssetsType1); |
619 | 619 | |
620 | 620 | List<Asset> loadedAssetsType2 = new ArrayList<>(); |
621 | - pageLink = new TextPageLink(4); | |
621 | + pageLink = new PageLink(4); | |
622 | 622 | do { |
623 | 623 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", |
624 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type2); | |
624 | + new TypeReference<PageData<Asset>>(){}, pageLink, type2); | |
625 | 625 | loadedAssetsType2.addAll(pageData.getData()); |
626 | 626 | if (pageData.hasNext()) { |
627 | - pageLink = pageData.getNextPageLink(); | |
627 | + pageLink = pageLink.nextPageLink(); | |
628 | 628 | } |
629 | 629 | } while (pageData.hasNext()); |
630 | 630 | |
... | ... | @@ -638,9 +638,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
638 | 638 | .andExpect(status().isOk()); |
639 | 639 | } |
640 | 640 | |
641 | - pageLink = new TextPageLink(4); | |
641 | + pageLink = new PageLink(4); | |
642 | 642 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", |
643 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type1); | |
643 | + new TypeReference<PageData<Asset>>(){}, pageLink, type1); | |
644 | 644 | Assert.assertFalse(pageData.hasNext()); |
645 | 645 | Assert.assertEquals(0, pageData.getData().size()); |
646 | 646 | |
... | ... | @@ -649,9 +649,9 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
649 | 649 | .andExpect(status().isOk()); |
650 | 650 | } |
651 | 651 | |
652 | - pageLink = new TextPageLink(4); | |
652 | + pageLink = new PageLink(4); | |
653 | 653 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", |
654 | - new TypeReference<TextPageData<Asset>>(){}, pageLink, type2); | |
654 | + new TypeReference<PageData<Asset>>(){}, pageLink, type2); | |
655 | 655 | Assert.assertFalse(pageData.hasNext()); |
656 | 656 | Assert.assertEquals(0, pageData.getData().size()); |
657 | 657 | } | ... | ... |
... | ... | @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.Device; |
24 | 24 | import org.thingsboard.server.common.data.Tenant; |
25 | 25 | import org.thingsboard.server.common.data.User; |
26 | 26 | import org.thingsboard.server.common.data.audit.AuditLog; |
27 | -import org.thingsboard.server.common.data.page.TimePageData; | |
27 | +import org.thingsboard.server.common.data.page.PageData; | |
28 | 28 | import org.thingsboard.server.common.data.page.TimePageLink; |
29 | 29 | import org.thingsboard.server.common.data.security.Authority; |
30 | 30 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -77,14 +77,14 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest |
77 | 77 | |
78 | 78 | List<AuditLog> loadedAuditLogs = new ArrayList<>(); |
79 | 79 | TimePageLink pageLink = new TimePageLink(23); |
80 | - TimePageData<AuditLog> pageData; | |
80 | + PageData<AuditLog> pageData; | |
81 | 81 | do { |
82 | 82 | pageData = doGetTypedWithTimePageLink("/api/audit/logs?", |
83 | - new TypeReference<TimePageData<AuditLog>>() { | |
83 | + new TypeReference<PageData<AuditLog>>() { | |
84 | 84 | }, pageLink); |
85 | 85 | loadedAuditLogs.addAll(pageData.getData()); |
86 | 86 | if (pageData.hasNext()) { |
87 | - pageLink = pageData.getNextPageLink(); | |
87 | + pageLink = pageLink.nextPageLink(); | |
88 | 88 | } |
89 | 89 | } while (pageData.hasNext()); |
90 | 90 | |
... | ... | @@ -94,11 +94,11 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest |
94 | 94 | pageLink = new TimePageLink(23); |
95 | 95 | do { |
96 | 96 | pageData = doGetTypedWithTimePageLink("/api/audit/logs/customer/" + ModelConstants.NULL_UUID + "?", |
97 | - new TypeReference<TimePageData<AuditLog>>() { | |
97 | + new TypeReference<PageData<AuditLog>>() { | |
98 | 98 | }, pageLink); |
99 | 99 | loadedAuditLogs.addAll(pageData.getData()); |
100 | 100 | if (pageData.hasNext()) { |
101 | - pageLink = pageData.getNextPageLink(); | |
101 | + pageLink = pageLink.nextPageLink(); | |
102 | 102 | } |
103 | 103 | } while (pageData.hasNext()); |
104 | 104 | |
... | ... | @@ -108,11 +108,11 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest |
108 | 108 | pageLink = new TimePageLink(23); |
109 | 109 | do { |
110 | 110 | pageData = doGetTypedWithTimePageLink("/api/audit/logs/user/" + tenantAdmin.getId().getId().toString() + "?", |
111 | - new TypeReference<TimePageData<AuditLog>>() { | |
111 | + new TypeReference<PageData<AuditLog>>() { | |
112 | 112 | }, pageLink); |
113 | 113 | loadedAuditLogs.addAll(pageData.getData()); |
114 | 114 | if (pageData.hasNext()) { |
115 | - pageLink = pageData.getNextPageLink(); | |
115 | + pageLink = pageLink.nextPageLink(); | |
116 | 116 | } |
117 | 117 | } while (pageData.hasNext()); |
118 | 118 | |
... | ... | @@ -132,14 +132,14 @@ public abstract class BaseAuditLogControllerTest extends AbstractControllerTest |
132 | 132 | |
133 | 133 | List<AuditLog> loadedAuditLogs = new ArrayList<>(); |
134 | 134 | TimePageLink pageLink = new TimePageLink(23); |
135 | - TimePageData<AuditLog> pageData; | |
135 | + PageData<AuditLog> pageData; | |
136 | 136 | do { |
137 | 137 | pageData = doGetTypedWithTimePageLink("/api/audit/logs/entity/DEVICE/" + savedDevice.getId().getId() + "?", |
138 | - new TypeReference<TimePageData<AuditLog>>() { | |
138 | + new TypeReference<PageData<AuditLog>>() { | |
139 | 139 | }, pageLink); |
140 | 140 | loadedAuditLogs.addAll(pageData.getData()); |
141 | 141 | if (pageData.hasNext()) { |
142 | - pageLink = pageData.getNextPageLink(); | |
142 | + pageLink = pageLink.nextPageLink(); | |
143 | 143 | } |
144 | 144 | } while (pageData.hasNext()); |
145 | 145 | ... | ... |
... | ... | @@ -27,8 +27,8 @@ import org.thingsboard.server.common.data.Customer; |
27 | 27 | import org.thingsboard.server.common.data.Tenant; |
28 | 28 | import org.thingsboard.server.common.data.User; |
29 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | -import org.thingsboard.server.common.data.page.TextPageData; | |
31 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
30 | +import org.thingsboard.server.common.data.page.PageData; | |
31 | +import org.thingsboard.server.common.data.page.PageLink; | |
32 | 32 | import org.thingsboard.server.common.data.security.Authority; |
33 | 33 | import org.junit.Assert; |
34 | 34 | import org.junit.Test; |
... | ... | @@ -241,13 +241,13 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
241 | 241 | } |
242 | 242 | |
243 | 243 | List<Customer> loadedCustomers = new ArrayList<>(); |
244 | - TextPageLink pageLink = new TextPageLink(23); | |
245 | - TextPageData<Customer> pageData = null; | |
244 | + PageLink pageLink = new PageLink(23); | |
245 | + PageData<Customer> pageData = null; | |
246 | 246 | do { |
247 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
247 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); | |
248 | 248 | loadedCustomers.addAll(pageData.getData()); |
249 | 249 | if (pageData.hasNext()) { |
250 | - pageLink = pageData.getNextPageLink(); | |
250 | + pageLink = pageLink.nextPageLink(); | |
251 | 251 | } |
252 | 252 | } while (pageData.hasNext()); |
253 | 253 | |
... | ... | @@ -307,13 +307,13 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
307 | 307 | } |
308 | 308 | |
309 | 309 | List<Customer> loadedCustomersTitle1 = new ArrayList<>(); |
310 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
311 | - TextPageData<Customer> pageData = null; | |
310 | + PageLink pageLink = new PageLink(15, 0, title1); | |
311 | + PageData<Customer> pageData = null; | |
312 | 312 | do { |
313 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
313 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); | |
314 | 314 | loadedCustomersTitle1.addAll(pageData.getData()); |
315 | 315 | if (pageData.hasNext()) { |
316 | - pageLink = pageData.getNextPageLink(); | |
316 | + pageLink = pageLink.nextPageLink(); | |
317 | 317 | } |
318 | 318 | } while (pageData.hasNext()); |
319 | 319 | |
... | ... | @@ -323,12 +323,12 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
323 | 323 | Assert.assertEquals(customersTitle1, loadedCustomersTitle1); |
324 | 324 | |
325 | 325 | List<Customer> loadedCustomersTitle2 = new ArrayList<>(); |
326 | - pageLink = new TextPageLink(4, title2); | |
326 | + pageLink = new PageLink(4, 0, title2); | |
327 | 327 | do { |
328 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
328 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); | |
329 | 329 | loadedCustomersTitle2.addAll(pageData.getData()); |
330 | 330 | if (pageData.hasNext()) { |
331 | - pageLink = pageData.getNextPageLink(); | |
331 | + pageLink = pageLink.nextPageLink(); | |
332 | 332 | } |
333 | 333 | } while (pageData.hasNext()); |
334 | 334 | |
... | ... | @@ -342,8 +342,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
342 | 342 | .andExpect(status().isOk()); |
343 | 343 | } |
344 | 344 | |
345 | - pageLink = new TextPageLink(4, title1); | |
346 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
345 | + pageLink = new PageLink(4, 0, title1); | |
346 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); | |
347 | 347 | Assert.assertFalse(pageData.hasNext()); |
348 | 348 | Assert.assertEquals(0, pageData.getData().size()); |
349 | 349 | |
... | ... | @@ -352,8 +352,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
352 | 352 | .andExpect(status().isOk()); |
353 | 353 | } |
354 | 354 | |
355 | - pageLink = new TextPageLink(4, title2); | |
356 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
355 | + pageLink = new PageLink(4, 0, title2); | |
356 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); | |
357 | 357 | Assert.assertFalse(pageData.hasNext()); |
358 | 358 | Assert.assertEquals(0, pageData.getData().size()); |
359 | 359 | ... | ... |
... | ... | @@ -28,9 +28,8 @@ import com.datastax.driver.core.utils.UUIDs; |
28 | 28 | import org.apache.commons.lang3.RandomStringUtils; |
29 | 29 | import org.thingsboard.server.common.data.*; |
30 | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
31 | -import org.thingsboard.server.common.data.page.TextPageData; | |
32 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
33 | -import org.thingsboard.server.common.data.page.TimePageData; | |
31 | +import org.thingsboard.server.common.data.page.PageData; | |
32 | +import org.thingsboard.server.common.data.page.PageLink; | |
34 | 33 | import org.thingsboard.server.common.data.page.TimePageLink; |
35 | 34 | import org.thingsboard.server.common.data.security.Authority; |
36 | 35 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -211,14 +210,14 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
211 | 210 | dashboards.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class))); |
212 | 211 | } |
213 | 212 | List<DashboardInfo> loadedDashboards = new ArrayList<>(); |
214 | - TextPageLink pageLink = new TextPageLink(24); | |
215 | - TextPageData<DashboardInfo> pageData = null; | |
213 | + PageLink pageLink = new PageLink(24); | |
214 | + PageData<DashboardInfo> pageData = null; | |
216 | 215 | do { |
217 | 216 | pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", |
218 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
217 | + new TypeReference<PageData<DashboardInfo>>(){}, pageLink); | |
219 | 218 | loadedDashboards.addAll(pageData.getData()); |
220 | 219 | if (pageData.hasNext()) { |
221 | - pageLink = pageData.getNextPageLink(); | |
220 | + pageLink = pageLink.nextPageLink(); | |
222 | 221 | } |
223 | 222 | } while (pageData.hasNext()); |
224 | 223 | |
... | ... | @@ -252,14 +251,14 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
252 | 251 | } |
253 | 252 | |
254 | 253 | List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>(); |
255 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
256 | - TextPageData<DashboardInfo> pageData = null; | |
254 | + PageLink pageLink = new PageLink(15, 0, title1); | |
255 | + PageData<DashboardInfo> pageData = null; | |
257 | 256 | do { |
258 | 257 | pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", |
259 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
258 | + new TypeReference<PageData<DashboardInfo>>(){}, pageLink); | |
260 | 259 | loadedDashboardsTitle1.addAll(pageData.getData()); |
261 | 260 | if (pageData.hasNext()) { |
262 | - pageLink = pageData.getNextPageLink(); | |
261 | + pageLink = pageLink.nextPageLink(); | |
263 | 262 | } |
264 | 263 | } while (pageData.hasNext()); |
265 | 264 | |
... | ... | @@ -269,13 +268,13 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
269 | 268 | Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1); |
270 | 269 | |
271 | 270 | List<DashboardInfo> loadedDashboardsTitle2 = new ArrayList<>(); |
272 | - pageLink = new TextPageLink(4, title2); | |
271 | + pageLink = new PageLink(4, 0, title2); | |
273 | 272 | do { |
274 | 273 | pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", |
275 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
274 | + new TypeReference<PageData<DashboardInfo>>(){}, pageLink); | |
276 | 275 | loadedDashboardsTitle2.addAll(pageData.getData()); |
277 | 276 | if (pageData.hasNext()) { |
278 | - pageLink = pageData.getNextPageLink(); | |
277 | + pageLink = pageLink.nextPageLink(); | |
279 | 278 | } |
280 | 279 | } while (pageData.hasNext()); |
281 | 280 | |
... | ... | @@ -289,9 +288,9 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
289 | 288 | .andExpect(status().isOk()); |
290 | 289 | } |
291 | 290 | |
292 | - pageLink = new TextPageLink(4, title1); | |
291 | + pageLink = new PageLink(4, 0, title1); | |
293 | 292 | pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", |
294 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
293 | + new TypeReference<PageData<DashboardInfo>>(){}, pageLink); | |
295 | 294 | Assert.assertFalse(pageData.hasNext()); |
296 | 295 | Assert.assertEquals(0, pageData.getData().size()); |
297 | 296 | |
... | ... | @@ -300,9 +299,9 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
300 | 299 | .andExpect(status().isOk()); |
301 | 300 | } |
302 | 301 | |
303 | - pageLink = new TextPageLink(4, title2); | |
302 | + pageLink = new PageLink(4, 0, title2); | |
304 | 303 | pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", |
305 | - new TypeReference<TextPageData<DashboardInfo>>(){}, pageLink); | |
304 | + new TypeReference<PageData<DashboardInfo>>(){}, pageLink); | |
306 | 305 | Assert.assertFalse(pageData.hasNext()); |
307 | 306 | Assert.assertEquals(0, pageData.getData().size()); |
308 | 307 | } |
... | ... | @@ -324,14 +323,14 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
324 | 323 | } |
325 | 324 | |
326 | 325 | List<DashboardInfo> loadedDashboards = new ArrayList<>(); |
327 | - TimePageLink pageLink = new TimePageLink(21); | |
328 | - TimePageData<DashboardInfo> pageData = null; | |
326 | + PageLink pageLink = new PageLink(21); | |
327 | + PageData<DashboardInfo> pageData = null; | |
329 | 328 | do { |
330 | - pageData = doGetTypedWithTimePageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
331 | - new TypeReference<TimePageData<DashboardInfo>>(){}, pageLink); | |
329 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", | |
330 | + new TypeReference<PageData<DashboardInfo>>(){}, pageLink); | |
332 | 331 | loadedDashboards.addAll(pageData.getData()); |
333 | 332 | if (pageData.hasNext()) { |
334 | - pageLink = pageData.getNextPageLink(); | |
333 | + pageLink = pageLink.nextPageLink(); | |
335 | 334 | } |
336 | 335 | } while (pageData.hasNext()); |
337 | 336 | ... | ... |
... | ... | @@ -29,8 +29,8 @@ import org.thingsboard.server.common.data.*; |
29 | 29 | import org.thingsboard.server.common.data.id.CustomerId; |
30 | 30 | import org.thingsboard.server.common.data.id.DeviceCredentialsId; |
31 | 31 | import org.thingsboard.server.common.data.id.DeviceId; |
32 | -import org.thingsboard.server.common.data.page.TextPageData; | |
33 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
32 | +import org.thingsboard.server.common.data.page.PageData; | |
33 | +import org.thingsboard.server.common.data.page.PageLink; | |
34 | 34 | import org.thingsboard.server.common.data.security.Authority; |
35 | 35 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
36 | 36 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
... | ... | @@ -366,14 +366,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
366 | 366 | devices.add(doPost("/api/device", device, Device.class)); |
367 | 367 | } |
368 | 368 | List<Device> loadedDevices = new ArrayList<>(); |
369 | - TextPageLink pageLink = new TextPageLink(23); | |
370 | - TextPageData<Device> pageData = null; | |
369 | + PageLink pageLink = new PageLink(23); | |
370 | + PageData<Device> pageData = null; | |
371 | 371 | do { |
372 | 372 | pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
373 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
373 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
374 | 374 | loadedDevices.addAll(pageData.getData()); |
375 | 375 | if (pageData.hasNext()) { |
376 | - pageLink = pageData.getNextPageLink(); | |
376 | + pageLink = pageLink.nextPageLink(); | |
377 | 377 | } |
378 | 378 | } while (pageData.hasNext()); |
379 | 379 | |
... | ... | @@ -409,14 +409,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
409 | 409 | } |
410 | 410 | |
411 | 411 | List<Device> loadedDevicesTitle1 = new ArrayList<>(); |
412 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
413 | - TextPageData<Device> pageData = null; | |
412 | + PageLink pageLink = new PageLink(15, 0, title1); | |
413 | + PageData<Device> pageData = null; | |
414 | 414 | do { |
415 | 415 | pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
416 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
416 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
417 | 417 | loadedDevicesTitle1.addAll(pageData.getData()); |
418 | 418 | if (pageData.hasNext()) { |
419 | - pageLink = pageData.getNextPageLink(); | |
419 | + pageLink = pageLink.nextPageLink(); | |
420 | 420 | } |
421 | 421 | } while (pageData.hasNext()); |
422 | 422 | |
... | ... | @@ -426,13 +426,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
426 | 426 | Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); |
427 | 427 | |
428 | 428 | List<Device> loadedDevicesTitle2 = new ArrayList<>(); |
429 | - pageLink = new TextPageLink(4, title2); | |
429 | + pageLink = new PageLink(4, 0, title2); | |
430 | 430 | do { |
431 | 431 | pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
432 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
432 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
433 | 433 | loadedDevicesTitle2.addAll(pageData.getData()); |
434 | 434 | if (pageData.hasNext()) { |
435 | - pageLink = pageData.getNextPageLink(); | |
435 | + pageLink = pageLink.nextPageLink(); | |
436 | 436 | } |
437 | 437 | } while (pageData.hasNext()); |
438 | 438 | |
... | ... | @@ -446,9 +446,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
446 | 446 | .andExpect(status().isOk()); |
447 | 447 | } |
448 | 448 | |
449 | - pageLink = new TextPageLink(4, title1); | |
449 | + pageLink = new PageLink(4, 0, title1); | |
450 | 450 | pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
451 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
451 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
452 | 452 | Assert.assertFalse(pageData.hasNext()); |
453 | 453 | Assert.assertEquals(0, pageData.getData().size()); |
454 | 454 | |
... | ... | @@ -457,9 +457,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
457 | 457 | .andExpect(status().isOk()); |
458 | 458 | } |
459 | 459 | |
460 | - pageLink = new TextPageLink(4, title2); | |
460 | + pageLink = new PageLink(4, 0, title2); | |
461 | 461 | pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
462 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
462 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
463 | 463 | Assert.assertFalse(pageData.hasNext()); |
464 | 464 | Assert.assertEquals(0, pageData.getData().size()); |
465 | 465 | } |
... | ... | @@ -492,14 +492,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
492 | 492 | } |
493 | 493 | |
494 | 494 | List<Device> loadedDevicesType1 = new ArrayList<>(); |
495 | - TextPageLink pageLink = new TextPageLink(15); | |
496 | - TextPageData<Device> pageData = null; | |
495 | + PageLink pageLink = new PageLink(15); | |
496 | + PageData<Device> pageData = null; | |
497 | 497 | do { |
498 | 498 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
499 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | |
499 | + new TypeReference<PageData<Device>>(){}, pageLink, type1); | |
500 | 500 | loadedDevicesType1.addAll(pageData.getData()); |
501 | 501 | if (pageData.hasNext()) { |
502 | - pageLink = pageData.getNextPageLink(); | |
502 | + pageLink = pageLink.nextPageLink(); | |
503 | 503 | } |
504 | 504 | } while (pageData.hasNext()); |
505 | 505 | |
... | ... | @@ -509,13 +509,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
509 | 509 | Assert.assertEquals(devicesType1, loadedDevicesType1); |
510 | 510 | |
511 | 511 | List<Device> loadedDevicesType2 = new ArrayList<>(); |
512 | - pageLink = new TextPageLink(4); | |
512 | + pageLink = new PageLink(4); | |
513 | 513 | do { |
514 | 514 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
515 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | |
515 | + new TypeReference<PageData<Device>>(){}, pageLink, type2); | |
516 | 516 | loadedDevicesType2.addAll(pageData.getData()); |
517 | 517 | if (pageData.hasNext()) { |
518 | - pageLink = pageData.getNextPageLink(); | |
518 | + pageLink = pageLink.nextPageLink(); | |
519 | 519 | } |
520 | 520 | } while (pageData.hasNext()); |
521 | 521 | |
... | ... | @@ -529,9 +529,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
529 | 529 | .andExpect(status().isOk()); |
530 | 530 | } |
531 | 531 | |
532 | - pageLink = new TextPageLink(4); | |
532 | + pageLink = new PageLink(4); | |
533 | 533 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
534 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | |
534 | + new TypeReference<PageData<Device>>(){}, pageLink, type1); | |
535 | 535 | Assert.assertFalse(pageData.hasNext()); |
536 | 536 | Assert.assertEquals(0, pageData.getData().size()); |
537 | 537 | |
... | ... | @@ -540,9 +540,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
540 | 540 | .andExpect(status().isOk()); |
541 | 541 | } |
542 | 542 | |
543 | - pageLink = new TextPageLink(4); | |
543 | + pageLink = new PageLink(4); | |
544 | 544 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
545 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | |
545 | + new TypeReference<PageData<Device>>(){}, pageLink, type2); | |
546 | 546 | Assert.assertFalse(pageData.hasNext()); |
547 | 547 | Assert.assertEquals(0, pageData.getData().size()); |
548 | 548 | } |
... | ... | @@ -565,14 +565,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
565 | 565 | } |
566 | 566 | |
567 | 567 | List<Device> loadedDevices = new ArrayList<>(); |
568 | - TextPageLink pageLink = new TextPageLink(23); | |
569 | - TextPageData<Device> pageData = null; | |
568 | + PageLink pageLink = new PageLink(23); | |
569 | + PageData<Device> pageData = null; | |
570 | 570 | do { |
571 | 571 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
572 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
572 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
573 | 573 | loadedDevices.addAll(pageData.getData()); |
574 | 574 | if (pageData.hasNext()) { |
575 | - pageLink = pageData.getNextPageLink(); | |
575 | + pageLink = pageLink.nextPageLink(); | |
576 | 576 | } |
577 | 577 | } while (pageData.hasNext()); |
578 | 578 | |
... | ... | @@ -617,14 +617,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
617 | 617 | } |
618 | 618 | |
619 | 619 | List<Device> loadedDevicesTitle1 = new ArrayList<>(); |
620 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
621 | - TextPageData<Device> pageData = null; | |
620 | + PageLink pageLink = new PageLink(15, 0, title1); | |
621 | + PageData<Device> pageData = null; | |
622 | 622 | do { |
623 | 623 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
624 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
624 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
625 | 625 | loadedDevicesTitle1.addAll(pageData.getData()); |
626 | 626 | if (pageData.hasNext()) { |
627 | - pageLink = pageData.getNextPageLink(); | |
627 | + pageLink = pageLink.nextPageLink(); | |
628 | 628 | } |
629 | 629 | } while (pageData.hasNext()); |
630 | 630 | |
... | ... | @@ -634,13 +634,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
634 | 634 | Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); |
635 | 635 | |
636 | 636 | List<Device> loadedDevicesTitle2 = new ArrayList<>(); |
637 | - pageLink = new TextPageLink(4, title2); | |
637 | + pageLink = new PageLink(4, 0, title2); | |
638 | 638 | do { |
639 | 639 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
640 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
640 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
641 | 641 | loadedDevicesTitle2.addAll(pageData.getData()); |
642 | 642 | if (pageData.hasNext()) { |
643 | - pageLink = pageData.getNextPageLink(); | |
643 | + pageLink = pageLink.nextPageLink(); | |
644 | 644 | } |
645 | 645 | } while (pageData.hasNext()); |
646 | 646 | |
... | ... | @@ -654,9 +654,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
654 | 654 | .andExpect(status().isOk()); |
655 | 655 | } |
656 | 656 | |
657 | - pageLink = new TextPageLink(4, title1); | |
657 | + pageLink = new PageLink(4, 0, title1); | |
658 | 658 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
659 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
659 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
660 | 660 | Assert.assertFalse(pageData.hasNext()); |
661 | 661 | Assert.assertEquals(0, pageData.getData().size()); |
662 | 662 | |
... | ... | @@ -665,9 +665,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
665 | 665 | .andExpect(status().isOk()); |
666 | 666 | } |
667 | 667 | |
668 | - pageLink = new TextPageLink(4, title2); | |
668 | + pageLink = new PageLink(4, 0, title2); | |
669 | 669 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
670 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | |
670 | + new TypeReference<PageData<Device>>(){}, pageLink); | |
671 | 671 | Assert.assertFalse(pageData.hasNext()); |
672 | 672 | Assert.assertEquals(0, pageData.getData().size()); |
673 | 673 | } |
... | ... | @@ -709,14 +709,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
709 | 709 | } |
710 | 710 | |
711 | 711 | List<Device> loadedDevicesType1 = new ArrayList<>(); |
712 | - TextPageLink pageLink = new TextPageLink(15); | |
713 | - TextPageData<Device> pageData = null; | |
712 | + PageLink pageLink = new PageLink(15); | |
713 | + PageData<Device> pageData = null; | |
714 | 714 | do { |
715 | 715 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
716 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | |
716 | + new TypeReference<PageData<Device>>(){}, pageLink, type1); | |
717 | 717 | loadedDevicesType1.addAll(pageData.getData()); |
718 | 718 | if (pageData.hasNext()) { |
719 | - pageLink = pageData.getNextPageLink(); | |
719 | + pageLink = pageLink.nextPageLink(); | |
720 | 720 | } |
721 | 721 | } while (pageData.hasNext()); |
722 | 722 | |
... | ... | @@ -726,13 +726,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
726 | 726 | Assert.assertEquals(devicesType1, loadedDevicesType1); |
727 | 727 | |
728 | 728 | List<Device> loadedDevicesType2 = new ArrayList<>(); |
729 | - pageLink = new TextPageLink(4); | |
729 | + pageLink = new PageLink(4); | |
730 | 730 | do { |
731 | 731 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
732 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | |
732 | + new TypeReference<PageData<Device>>(){}, pageLink, type2); | |
733 | 733 | loadedDevicesType2.addAll(pageData.getData()); |
734 | 734 | if (pageData.hasNext()) { |
735 | - pageLink = pageData.getNextPageLink(); | |
735 | + pageLink = pageLink.nextPageLink(); | |
736 | 736 | } |
737 | 737 | } while (pageData.hasNext()); |
738 | 738 | |
... | ... | @@ -746,9 +746,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
746 | 746 | .andExpect(status().isOk()); |
747 | 747 | } |
748 | 748 | |
749 | - pageLink = new TextPageLink(4); | |
749 | + pageLink = new PageLink(4); | |
750 | 750 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
751 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | |
751 | + new TypeReference<PageData<Device>>(){}, pageLink, type1); | |
752 | 752 | Assert.assertFalse(pageData.hasNext()); |
753 | 753 | Assert.assertEquals(0, pageData.getData().size()); |
754 | 754 | |
... | ... | @@ -757,9 +757,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
757 | 757 | .andExpect(status().isOk()); |
758 | 758 | } |
759 | 759 | |
760 | - pageLink = new TextPageLink(4); | |
760 | + pageLink = new PageLink(4); | |
761 | 761 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
762 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | |
762 | + new TypeReference<PageData<Device>>(){}, pageLink, type2); | |
763 | 763 | Assert.assertFalse(pageData.hasNext()); |
764 | 764 | Assert.assertEquals(0, pageData.getData().size()); |
765 | 765 | } | ... | ... |
... | ... | @@ -25,16 +25,12 @@ import org.junit.After; |
25 | 25 | import org.junit.Assert; |
26 | 26 | import org.junit.Before; |
27 | 27 | import org.junit.Test; |
28 | -import org.thingsboard.server.common.data.Customer; | |
29 | -import org.thingsboard.server.common.data.Device; | |
30 | -import org.thingsboard.server.common.data.EntityView; | |
31 | -import org.thingsboard.server.common.data.Tenant; | |
32 | -import org.thingsboard.server.common.data.User; | |
28 | +import org.thingsboard.server.common.data.*; | |
33 | 29 | import org.thingsboard.server.common.data.id.CustomerId; |
34 | 30 | import org.thingsboard.server.common.data.objects.AttributesEntityView; |
35 | 31 | import org.thingsboard.server.common.data.objects.TelemetryEntityView; |
36 | -import org.thingsboard.server.common.data.page.TextPageData; | |
37 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
32 | +import org.thingsboard.server.common.data.page.PageData; | |
33 | +import org.thingsboard.server.common.data.page.PageLink; | |
38 | 34 | import org.thingsboard.server.common.data.security.Authority; |
39 | 35 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
40 | 36 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -214,16 +210,20 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
214 | 210 | |
215 | 211 | @Test |
216 | 212 | public void testGetCustomerEntityViews() throws Exception { |
217 | - CustomerId customerId = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class).getId(); | |
218 | - String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; | |
213 | + Customer customer = doPost("/api/customer", getNewCustomer("Test customer"), Customer.class); | |
214 | + CustomerId customerId = customer.getId(); | |
215 | + String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViewInfos?"; | |
219 | 216 | |
220 | - List<EntityView> views = new ArrayList<>(); | |
217 | + List<EntityViewInfo> views = new ArrayList<>(); | |
221 | 218 | for (int i = 0; i < 128; i++) { |
222 | - views.add(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/" | |
223 | - + getNewSavedEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class)); | |
219 | + views.add( | |
220 | + new EntityViewInfo(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/" | |
221 | + + getNewSavedEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class), | |
222 | + customer.getTitle(), customer.isPublic()) | |
223 | + ); | |
224 | 224 | } |
225 | 225 | |
226 | - List<EntityView> loadedViews = loadListOf(new TextPageLink(23), urlTemplate); | |
226 | + List<EntityViewInfo> loadedViews = loadListOfInfo(new PageLink(23), urlTemplate); | |
227 | 227 | |
228 | 228 | Collections.sort(views, idComparator); |
229 | 229 | Collections.sort(loadedViews, idComparator); |
... | ... | @@ -239,7 +239,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
239 | 239 | String name1 = "Entity view name1"; |
240 | 240 | List<EntityView> namesOfView1 = fillListOf(125, name1, "/api/customer/" + customerId.getId().toString() |
241 | 241 | + "/entityView/"); |
242 | - List<EntityView> loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), urlTemplate); | |
242 | + List<EntityView> loadedNamesOfView1 = loadListOf(new PageLink(15, 0, name1), urlTemplate); | |
243 | 243 | Collections.sort(namesOfView1, idComparator); |
244 | 244 | Collections.sort(loadedNamesOfView1, idComparator); |
245 | 245 | assertEquals(namesOfView1, loadedNamesOfView1); |
... | ... | @@ -247,7 +247,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
247 | 247 | String name2 = "Entity view name2"; |
248 | 248 | List<EntityView> NamesOfView2 = fillListOf(143, name2, "/api/customer/" + customerId.getId().toString() |
249 | 249 | + "/entityView/"); |
250 | - List<EntityView> loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), urlTemplate); | |
250 | + List<EntityView> loadedNamesOfView2 = loadListOf(new PageLink(4, 0, name2), urlTemplate); | |
251 | 251 | Collections.sort(NamesOfView2, idComparator); |
252 | 252 | Collections.sort(loadedNamesOfView2, idComparator); |
253 | 253 | assertEquals(NamesOfView2, loadedNamesOfView2); |
... | ... | @@ -255,18 +255,18 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
255 | 255 | for (EntityView view : loadedNamesOfView1) { |
256 | 256 | doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); |
257 | 257 | } |
258 | - TextPageData<EntityView> pageData = doGetTypedWithPageLink(urlTemplate, | |
259 | - new TypeReference<TextPageData<EntityView>>() { | |
260 | - }, new TextPageLink(4, name1)); | |
258 | + PageData<EntityView> pageData = doGetTypedWithPageLink(urlTemplate, | |
259 | + new TypeReference<PageData<EntityView>>() { | |
260 | + }, new PageLink(4, 0, name1)); | |
261 | 261 | Assert.assertFalse(pageData.hasNext()); |
262 | 262 | assertEquals(0, pageData.getData().size()); |
263 | 263 | |
264 | 264 | for (EntityView view : loadedNamesOfView2) { |
265 | 265 | doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); |
266 | 266 | } |
267 | - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<TextPageData<EntityView>>() { | |
267 | + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<PageData<EntityView>>() { | |
268 | 268 | }, |
269 | - new TextPageLink(4, name2)); | |
269 | + new PageLink(4, 0, name2)); | |
270 | 270 | Assert.assertFalse(pageData.hasNext()); |
271 | 271 | assertEquals(0, pageData.getData().size()); |
272 | 272 | } |
... | ... | @@ -274,11 +274,11 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
274 | 274 | @Test |
275 | 275 | public void testGetTenantEntityViews() throws Exception { |
276 | 276 | |
277 | - List<EntityView> views = new ArrayList<>(); | |
277 | + List<EntityViewInfo> views = new ArrayList<>(); | |
278 | 278 | for (int i = 0; i < 178; i++) { |
279 | - views.add(getNewSavedEntityView("Test entity view" + i)); | |
279 | + views.add(new EntityViewInfo(getNewSavedEntityView("Test entity view" + i), null, false)); | |
280 | 280 | } |
281 | - List<EntityView> loadedViews = loadListOf(new TextPageLink(23), "/api/tenant/entityViews?"); | |
281 | + List<EntityViewInfo> loadedViews = loadListOfInfo(new PageLink(23), "/api/tenant/entityViewInfos?"); | |
282 | 282 | |
283 | 283 | Collections.sort(views, idComparator); |
284 | 284 | Collections.sort(loadedViews, idComparator); |
... | ... | @@ -290,14 +290,14 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
290 | 290 | public void testGetTenantEntityViewsByName() throws Exception { |
291 | 291 | String name1 = "Entity view name1"; |
292 | 292 | List<EntityView> namesOfView1 = fillListOf(143, name1); |
293 | - List<EntityView> loadedNamesOfView1 = loadListOf(new TextPageLink(15, name1), "/api/tenant/entityViews?"); | |
293 | + List<EntityView> loadedNamesOfView1 = loadListOf(new PageLink(15, 0, name1), "/api/tenant/entityViews?"); | |
294 | 294 | Collections.sort(namesOfView1, idComparator); |
295 | 295 | Collections.sort(loadedNamesOfView1, idComparator); |
296 | 296 | assertEquals(namesOfView1, loadedNamesOfView1); |
297 | 297 | |
298 | 298 | String name2 = "Entity view name2"; |
299 | 299 | List<EntityView> NamesOfView2 = fillListOf(75, name2); |
300 | - List<EntityView> loadedNamesOfView2 = loadListOf(new TextPageLink(4, name2), "/api/tenant/entityViews?"); | |
300 | + List<EntityView> loadedNamesOfView2 = loadListOf(new PageLink(4, 0, name2), "/api/tenant/entityViews?"); | |
301 | 301 | Collections.sort(NamesOfView2, idComparator); |
302 | 302 | Collections.sort(loadedNamesOfView2, idComparator); |
303 | 303 | assertEquals(NamesOfView2, loadedNamesOfView2); |
... | ... | @@ -305,18 +305,18 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
305 | 305 | for (EntityView view : loadedNamesOfView1) { |
306 | 306 | doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); |
307 | 307 | } |
308 | - TextPageData<EntityView> pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", | |
309 | - new TypeReference<TextPageData<EntityView>>() { | |
310 | - }, new TextPageLink(4, name1)); | |
308 | + PageData<EntityView> pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", | |
309 | + new TypeReference<PageData<EntityView>>() { | |
310 | + }, new PageLink(4, 0, name1)); | |
311 | 311 | Assert.assertFalse(pageData.hasNext()); |
312 | 312 | assertEquals(0, pageData.getData().size()); |
313 | 313 | |
314 | 314 | for (EntityView view : loadedNamesOfView2) { |
315 | 315 | doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); |
316 | 316 | } |
317 | - pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference<TextPageData<EntityView>>() { | |
317 | + pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference<PageData<EntityView>>() { | |
318 | 318 | }, |
319 | - new TextPageLink(4, name2)); | |
319 | + new PageLink(4, 0, name2)); | |
320 | 320 | Assert.assertFalse(pageData.hasNext()); |
321 | 321 | assertEquals(0, pageData.getData().size()); |
322 | 322 | } |
... | ... | @@ -516,15 +516,30 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
516 | 516 | return viewNames; |
517 | 517 | } |
518 | 518 | |
519 | - private List<EntityView> loadListOf(TextPageLink pageLink, String urlTemplate) throws Exception { | |
519 | + private List<EntityView> loadListOf(PageLink pageLink, String urlTemplate) throws Exception { | |
520 | 520 | List<EntityView> loadedItems = new ArrayList<>(); |
521 | - TextPageData<EntityView> pageData; | |
521 | + PageData<EntityView> pageData; | |
522 | + do { | |
523 | + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<PageData<EntityView>>() { | |
524 | + }, pageLink); | |
525 | + loadedItems.addAll(pageData.getData()); | |
526 | + if (pageData.hasNext()) { | |
527 | + pageLink = pageLink.nextPageLink(); | |
528 | + } | |
529 | + } while (pageData.hasNext()); | |
530 | + | |
531 | + return loadedItems; | |
532 | + } | |
533 | + | |
534 | + private List<EntityViewInfo> loadListOfInfo(PageLink pageLink, String urlTemplate) throws Exception { | |
535 | + List<EntityViewInfo> loadedItems = new ArrayList<>(); | |
536 | + PageData<EntityViewInfo> pageData; | |
522 | 537 | do { |
523 | - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<TextPageData<EntityView>>() { | |
538 | + pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<PageData<EntityViewInfo>>() { | |
524 | 539 | }, pageLink); |
525 | 540 | loadedItems.addAll(pageData.getData()); |
526 | 541 | if (pageData.hasNext()) { |
527 | - pageLink = pageData.getNextPageLink(); | |
542 | + pageLink = pageLink.nextPageLink(); | |
528 | 543 | } |
529 | 544 | } while (pageData.hasNext()); |
530 | 545 | ... | ... |
... | ... | @@ -24,8 +24,8 @@ import java.util.List; |
24 | 24 | |
25 | 25 | import org.apache.commons.lang3.RandomStringUtils; |
26 | 26 | import org.thingsboard.server.common.data.Tenant; |
27 | -import org.thingsboard.server.common.data.page.TextPageData; | |
28 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
27 | +import org.thingsboard.server.common.data.page.PageData; | |
28 | +import org.thingsboard.server.common.data.page.PageLink; | |
29 | 29 | import org.junit.Assert; |
30 | 30 | import org.junit.Test; |
31 | 31 | |
... | ... | @@ -102,8 +102,8 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
102 | 102 | public void testFindTenants() throws Exception { |
103 | 103 | loginSysAdmin(); |
104 | 104 | List<Tenant> tenants = new ArrayList<>(); |
105 | - TextPageLink pageLink = new TextPageLink(17); | |
106 | - TextPageData<Tenant> pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
105 | + PageLink pageLink = new PageLink(17); | |
106 | + PageData<Tenant> pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
107 | 107 | Assert.assertFalse(pageData.hasNext()); |
108 | 108 | Assert.assertEquals(1, pageData.getData().size()); |
109 | 109 | tenants.addAll(pageData.getData()); |
... | ... | @@ -115,12 +115,12 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
115 | 115 | } |
116 | 116 | |
117 | 117 | List<Tenant> loadedTenants = new ArrayList<>(); |
118 | - pageLink = new TextPageLink(17); | |
118 | + pageLink = new PageLink(17); | |
119 | 119 | do { |
120 | - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
120 | + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
121 | 121 | loadedTenants.addAll(pageData.getData()); |
122 | 122 | if (pageData.hasNext()) { |
123 | - pageLink = pageData.getNextPageLink(); | |
123 | + pageLink = pageLink.nextPageLink(); | |
124 | 124 | } |
125 | 125 | } while (pageData.hasNext()); |
126 | 126 | |
... | ... | @@ -136,8 +136,8 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
136 | 136 | } |
137 | 137 | } |
138 | 138 | |
139 | - pageLink = new TextPageLink(17); | |
140 | - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
139 | + pageLink = new PageLink(17); | |
140 | + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
141 | 141 | Assert.assertFalse(pageData.hasNext()); |
142 | 142 | Assert.assertEquals(1, pageData.getData().size()); |
143 | 143 | } |
... | ... | @@ -167,13 +167,13 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
167 | 167 | } |
168 | 168 | |
169 | 169 | List<Tenant> loadedTenantsTitle1 = new ArrayList<>(); |
170 | - TextPageLink pageLink = new TextPageLink(15, title1); | |
171 | - TextPageData<Tenant> pageData = null; | |
170 | + PageLink pageLink = new PageLink(15, 0, title1); | |
171 | + PageData<Tenant> pageData = null; | |
172 | 172 | do { |
173 | - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
173 | + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
174 | 174 | loadedTenantsTitle1.addAll(pageData.getData()); |
175 | 175 | if (pageData.hasNext()) { |
176 | - pageLink = pageData.getNextPageLink(); | |
176 | + pageLink = pageLink.nextPageLink(); | |
177 | 177 | } |
178 | 178 | } while (pageData.hasNext()); |
179 | 179 | |
... | ... | @@ -183,12 +183,12 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
183 | 183 | Assert.assertEquals(tenantsTitle1, loadedTenantsTitle1); |
184 | 184 | |
185 | 185 | List<Tenant> loadedTenantsTitle2 = new ArrayList<>(); |
186 | - pageLink = new TextPageLink(4, title2); | |
186 | + pageLink = new PageLink(4, 0, title2); | |
187 | 187 | do { |
188 | - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
188 | + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
189 | 189 | loadedTenantsTitle2.addAll(pageData.getData()); |
190 | 190 | if (pageData.hasNext()) { |
191 | - pageLink = pageData.getNextPageLink(); | |
191 | + pageLink = pageLink.nextPageLink(); | |
192 | 192 | } |
193 | 193 | } while (pageData.hasNext()); |
194 | 194 | |
... | ... | @@ -202,8 +202,8 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
202 | 202 | .andExpect(status().isOk()); |
203 | 203 | } |
204 | 204 | |
205 | - pageLink = new TextPageLink(4, title1); | |
206 | - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
205 | + pageLink = new PageLink(4, 0, title1); | |
206 | + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
207 | 207 | Assert.assertFalse(pageData.hasNext()); |
208 | 208 | Assert.assertEquals(0, pageData.getData().size()); |
209 | 209 | |
... | ... | @@ -212,8 +212,8 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest { |
212 | 212 | .andExpect(status().isOk()); |
213 | 213 | } |
214 | 214 | |
215 | - pageLink = new TextPageLink(4, title2); | |
216 | - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<TextPageData<Tenant>>(){}, pageLink); | |
215 | + pageLink = new PageLink(4, 0, title2); | |
216 | + pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); | |
217 | 217 | Assert.assertFalse(pageData.hasNext()); |
218 | 218 | Assert.assertEquals(0, pageData.getData().size()); |
219 | 219 | } | ... | ... |
... | ... | @@ -27,8 +27,8 @@ import org.thingsboard.server.common.data.Tenant; |
27 | 27 | import org.thingsboard.server.common.data.User; |
28 | 28 | import org.thingsboard.server.common.data.id.CustomerId; |
29 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | -import org.thingsboard.server.common.data.page.TextPageData; | |
31 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
30 | +import org.thingsboard.server.common.data.page.PageData; | |
31 | +import org.thingsboard.server.common.data.page.PageLink; | |
32 | 32 | import org.thingsboard.server.common.data.security.Authority; |
33 | 33 | import org.thingsboard.server.service.mail.TestMailService; |
34 | 34 | |
... | ... | @@ -326,14 +326,14 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
326 | 326 | } |
327 | 327 | |
328 | 328 | List<User> loadedTenantAdmins = new ArrayList<>(); |
329 | - TextPageLink pageLink = new TextPageLink(33); | |
330 | - TextPageData<User> pageData = null; | |
329 | + PageLink pageLink = new PageLink(33); | |
330 | + PageData<User> pageData = null; | |
331 | 331 | do { |
332 | 332 | pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", |
333 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
333 | + new TypeReference<PageData<User>>(){}, pageLink); | |
334 | 334 | loadedTenantAdmins.addAll(pageData.getData()); |
335 | 335 | if (pageData.hasNext()) { |
336 | - pageLink = pageData.getNextPageLink(); | |
336 | + pageLink = pageLink.nextPageLink(); | |
337 | 337 | } |
338 | 338 | } while (pageData.hasNext()); |
339 | 339 | |
... | ... | @@ -345,9 +345,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
345 | 345 | doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) |
346 | 346 | .andExpect(status().isOk()); |
347 | 347 | |
348 | - pageLink = new TextPageLink(33); | |
348 | + pageLink = new PageLink(33); | |
349 | 349 | pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", |
350 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
350 | + new TypeReference<PageData<User>>(){}, pageLink); | |
351 | 351 | Assert.assertFalse(pageData.hasNext()); |
352 | 352 | Assert.assertTrue(pageData.getData().isEmpty()); |
353 | 353 | } |
... | ... | @@ -393,14 +393,14 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
393 | 393 | } |
394 | 394 | |
395 | 395 | List<User> loadedTenantAdminsEmail1 = new ArrayList<>(); |
396 | - TextPageLink pageLink = new TextPageLink(33, email1); | |
397 | - TextPageData<User> pageData = null; | |
396 | + PageLink pageLink = new PageLink(33, 0, email1); | |
397 | + PageData<User> pageData = null; | |
398 | 398 | do { |
399 | 399 | pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", |
400 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
400 | + new TypeReference<PageData<User>>(){}, pageLink); | |
401 | 401 | loadedTenantAdminsEmail1.addAll(pageData.getData()); |
402 | 402 | if (pageData.hasNext()) { |
403 | - pageLink = pageData.getNextPageLink(); | |
403 | + pageLink = pageLink.nextPageLink(); | |
404 | 404 | } |
405 | 405 | } while (pageData.hasNext()); |
406 | 406 | |
... | ... | @@ -410,13 +410,13 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
410 | 410 | Assert.assertEquals(tenantAdminsEmail1, loadedTenantAdminsEmail1); |
411 | 411 | |
412 | 412 | List<User> loadedTenantAdminsEmail2 = new ArrayList<>(); |
413 | - pageLink = new TextPageLink(16, email2); | |
413 | + pageLink = new PageLink(16, 0, email2); | |
414 | 414 | do { |
415 | 415 | pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", |
416 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
416 | + new TypeReference<PageData<User>>(){}, pageLink); | |
417 | 417 | loadedTenantAdminsEmail2.addAll(pageData.getData()); |
418 | 418 | if (pageData.hasNext()) { |
419 | - pageLink = pageData.getNextPageLink(); | |
419 | + pageLink = pageLink.nextPageLink(); | |
420 | 420 | } |
421 | 421 | } while (pageData.hasNext()); |
422 | 422 | |
... | ... | @@ -430,9 +430,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
430 | 430 | .andExpect(status().isOk()); |
431 | 431 | } |
432 | 432 | |
433 | - pageLink = new TextPageLink(4, email1); | |
433 | + pageLink = new PageLink(4, 0, email1); | |
434 | 434 | pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", |
435 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
435 | + new TypeReference<PageData<User>>(){}, pageLink); | |
436 | 436 | Assert.assertFalse(pageData.hasNext()); |
437 | 437 | Assert.assertEquals(0, pageData.getData().size()); |
438 | 438 | |
... | ... | @@ -441,9 +441,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
441 | 441 | .andExpect(status().isOk()); |
442 | 442 | } |
443 | 443 | |
444 | - pageLink = new TextPageLink(4, email2); | |
444 | + pageLink = new PageLink(4, 0, email2); | |
445 | 445 | pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", |
446 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
446 | + new TypeReference<PageData<User>>(){}, pageLink); | |
447 | 447 | Assert.assertFalse(pageData.hasNext()); |
448 | 448 | Assert.assertEquals(0, pageData.getData().size()); |
449 | 449 | |
... | ... | @@ -486,14 +486,14 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
486 | 486 | } |
487 | 487 | |
488 | 488 | List<User> loadedCustomerUsers = new ArrayList<>(); |
489 | - TextPageLink pageLink = new TextPageLink(33); | |
490 | - TextPageData<User> pageData = null; | |
489 | + PageLink pageLink = new PageLink(33); | |
490 | + PageData<User> pageData = null; | |
491 | 491 | do { |
492 | 492 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", |
493 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
493 | + new TypeReference<PageData<User>>(){}, pageLink); | |
494 | 494 | loadedCustomerUsers.addAll(pageData.getData()); |
495 | 495 | if (pageData.hasNext()) { |
496 | - pageLink = pageData.getNextPageLink(); | |
496 | + pageLink = pageLink.nextPageLink(); | |
497 | 497 | } |
498 | 498 | } while (pageData.hasNext()); |
499 | 499 | |
... | ... | @@ -565,14 +565,14 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
565 | 565 | } |
566 | 566 | |
567 | 567 | List<User> loadedCustomerUsersEmail1 = new ArrayList<>(); |
568 | - TextPageLink pageLink = new TextPageLink(33, email1); | |
569 | - TextPageData<User> pageData = null; | |
568 | + PageLink pageLink = new PageLink(33, 0, email1); | |
569 | + PageData<User> pageData = null; | |
570 | 570 | do { |
571 | 571 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", |
572 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
572 | + new TypeReference<PageData<User>>(){}, pageLink); | |
573 | 573 | loadedCustomerUsersEmail1.addAll(pageData.getData()); |
574 | 574 | if (pageData.hasNext()) { |
575 | - pageLink = pageData.getNextPageLink(); | |
575 | + pageLink = pageLink.nextPageLink(); | |
576 | 576 | } |
577 | 577 | } while (pageData.hasNext()); |
578 | 578 | |
... | ... | @@ -582,13 +582,13 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
582 | 582 | Assert.assertEquals(customerUsersEmail1, loadedCustomerUsersEmail1); |
583 | 583 | |
584 | 584 | List<User> loadedCustomerUsersEmail2 = new ArrayList<>(); |
585 | - pageLink = new TextPageLink(16, email2); | |
585 | + pageLink = new PageLink(16, 0, email2); | |
586 | 586 | do { |
587 | 587 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", |
588 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
588 | + new TypeReference<PageData<User>>(){}, pageLink); | |
589 | 589 | loadedCustomerUsersEmail2.addAll(pageData.getData()); |
590 | 590 | if (pageData.hasNext()) { |
591 | - pageLink = pageData.getNextPageLink(); | |
591 | + pageLink = pageLink.nextPageLink(); | |
592 | 592 | } |
593 | 593 | } while (pageData.hasNext()); |
594 | 594 | |
... | ... | @@ -602,9 +602,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
602 | 602 | .andExpect(status().isOk()); |
603 | 603 | } |
604 | 604 | |
605 | - pageLink = new TextPageLink(4, email1); | |
605 | + pageLink = new PageLink(4, 0, email1); | |
606 | 606 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", |
607 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
607 | + new TypeReference<PageData<User>>(){}, pageLink); | |
608 | 608 | Assert.assertFalse(pageData.hasNext()); |
609 | 609 | Assert.assertEquals(0, pageData.getData().size()); |
610 | 610 | |
... | ... | @@ -613,9 +613,9 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
613 | 613 | .andExpect(status().isOk()); |
614 | 614 | } |
615 | 615 | |
616 | - pageLink = new TextPageLink(4, email2); | |
616 | + pageLink = new PageLink(4, 0, email2); | |
617 | 617 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", |
618 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
618 | + new TypeReference<PageData<User>>(){}, pageLink); | |
619 | 619 | Assert.assertFalse(pageData.hasNext()); |
620 | 620 | Assert.assertEquals(0, pageData.getData().size()); |
621 | 621 | ... | ... |
... | ... | @@ -22,8 +22,8 @@ import org.junit.Before; |
22 | 22 | import org.junit.Test; |
23 | 23 | import org.thingsboard.server.common.data.Tenant; |
24 | 24 | import org.thingsboard.server.common.data.User; |
25 | -import org.thingsboard.server.common.data.page.TextPageData; | |
26 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
25 | +import org.thingsboard.server.common.data.page.PageData; | |
26 | +import org.thingsboard.server.common.data.page.PageLink; | |
27 | 27 | import org.thingsboard.server.common.data.security.Authority; |
28 | 28 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
29 | 29 | |
... | ... | @@ -150,14 +150,14 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController |
150 | 150 | widgetsBundles.addAll(sysWidgetsBundles); |
151 | 151 | |
152 | 152 | List<WidgetsBundle> loadedWidgetsBundles = new ArrayList<>(); |
153 | - TextPageLink pageLink = new TextPageLink(14); | |
154 | - TextPageData<WidgetsBundle> pageData; | |
153 | + PageLink pageLink = new PageLink(14); | |
154 | + PageData<WidgetsBundle> pageData; | |
155 | 155 | do { |
156 | 156 | pageData = doGetTypedWithPageLink("/api/widgetsBundles?", |
157 | - new TypeReference<TextPageData<WidgetsBundle>>(){}, pageLink); | |
157 | + new TypeReference<PageData<WidgetsBundle>>(){}, pageLink); | |
158 | 158 | loadedWidgetsBundles.addAll(pageData.getData()); |
159 | 159 | if (pageData.hasNext()) { |
160 | - pageLink = pageData.getNextPageLink(); | |
160 | + pageLink = pageLink.nextPageLink(); | |
161 | 161 | } |
162 | 162 | } while (pageData.hasNext()); |
163 | 163 | |
... | ... | @@ -186,14 +186,14 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController |
186 | 186 | widgetsBundles.addAll(sysWidgetsBundles); |
187 | 187 | |
188 | 188 | List<WidgetsBundle> loadedWidgetsBundles = new ArrayList<>(); |
189 | - TextPageLink pageLink = new TextPageLink(14); | |
190 | - TextPageData<WidgetsBundle> pageData; | |
189 | + PageLink pageLink = new PageLink(14); | |
190 | + PageData<WidgetsBundle> pageData; | |
191 | 191 | do { |
192 | 192 | pageData = doGetTypedWithPageLink("/api/widgetsBundles?", |
193 | - new TypeReference<TextPageData<WidgetsBundle>>(){}, pageLink); | |
193 | + new TypeReference<PageData<WidgetsBundle>>(){}, pageLink); | |
194 | 194 | loadedWidgetsBundles.addAll(pageData.getData()); |
195 | 195 | if (pageData.hasNext()) { |
196 | - pageLink = pageData.getNextPageLink(); | |
196 | + pageLink = pageLink.nextPageLink(); | |
197 | 197 | } |
198 | 198 | } while (pageData.hasNext()); |
199 | 199 | |
... | ... | @@ -207,14 +207,14 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController |
207 | 207 | .andExpect(status().isOk()); |
208 | 208 | } |
209 | 209 | |
210 | - pageLink = new TextPageLink(17); | |
210 | + pageLink = new PageLink(17); | |
211 | 211 | loadedWidgetsBundles.clear(); |
212 | 212 | do { |
213 | 213 | pageData = doGetTypedWithPageLink("/api/widgetsBundles?", |
214 | - new TypeReference<TextPageData<WidgetsBundle>>(){}, pageLink); | |
214 | + new TypeReference<PageData<WidgetsBundle>>(){}, pageLink); | |
215 | 215 | loadedWidgetsBundles.addAll(pageData.getData()); |
216 | 216 | if (pageData.hasNext()) { |
217 | - pageLink = pageData.getNextPageLink(); | |
217 | + pageLink = pageLink.nextPageLink(); | |
218 | 218 | } |
219 | 219 | } while (pageData.hasNext()); |
220 | 220 | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import org.junit.ClassRule; |
20 | 20 | import org.junit.extensions.cpsuite.ClasspathSuite; |
21 | 21 | import org.junit.runner.RunWith; |
22 | 22 | import org.thingsboard.server.dao.CustomCassandraCQLUnit; |
23 | +import org.thingsboard.server.dao.CustomSqlUnit; | |
23 | 24 | |
24 | 25 | import java.util.Arrays; |
25 | 26 | |
... | ... | @@ -29,11 +30,15 @@ import java.util.Arrays; |
29 | 30 | public class MqttNoSqlTestSuite { |
30 | 31 | |
31 | 32 | @ClassRule |
33 | + public static CustomSqlUnit sqlUnit = new CustomSqlUnit( | |
34 | + Arrays.asList("sql/schema-entities-hsql.sql", "sql/system-data.sql"), | |
35 | + "sql/drop-all-tables.sql", | |
36 | + "nosql-test.properties"); | |
37 | + | |
38 | + @ClassRule | |
32 | 39 | public static CustomCassandraCQLUnit cassandraUnit = |
33 | 40 | new CustomCassandraCQLUnit( |
34 | 41 | Arrays.asList( |
35 | - new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), | |
36 | - new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), | |
37 | - new ClassPathCQLDataSet("cassandra/system-data.cql", false, false)), | |
42 | + new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false)), | |
38 | 43 | "cassandra-test.yaml", 30000l); |
39 | 44 | } | ... | ... |
... | ... | @@ -30,8 +30,7 @@ import org.thingsboard.server.actors.service.ActorService; |
30 | 30 | import org.thingsboard.server.common.data.*; |
31 | 31 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
32 | 32 | import org.thingsboard.server.common.data.kv.StringDataEntry; |
33 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
34 | -import org.thingsboard.server.common.data.page.TimePageData; | |
33 | +import org.thingsboard.server.common.data.page.PageData; | |
35 | 34 | import org.thingsboard.server.common.data.rule.RuleChain; |
36 | 35 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
37 | 36 | import org.thingsboard.server.common.data.rule.RuleNode; |
... | ... | @@ -160,7 +159,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
160 | 159 | |
161 | 160 | Thread.sleep(3000); |
162 | 161 | |
163 | - TimePageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); | |
162 | + PageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); | |
164 | 163 | List<Event> events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); |
165 | 164 | Assert.assertEquals(2, events.size()); |
166 | 165 | |
... | ... | @@ -275,7 +274,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
275 | 274 | |
276 | 275 | Thread.sleep(3000); |
277 | 276 | |
278 | - TimePageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), rootRuleChain.getFirstRuleNodeId(), 1000); | |
277 | + PageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), rootRuleChain.getFirstRuleNodeId(), 1000); | |
279 | 278 | List<Event> events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); |
280 | 279 | |
281 | 280 | Assert.assertEquals(2, events.size()); | ... | ... |
... | ... | @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.Tenant; |
32 | 32 | import org.thingsboard.server.common.data.User; |
33 | 33 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
34 | 34 | import org.thingsboard.server.common.data.kv.StringDataEntry; |
35 | -import org.thingsboard.server.common.data.page.TimePageData; | |
35 | +import org.thingsboard.server.common.data.page.PageData; | |
36 | 36 | import org.thingsboard.server.common.data.rule.RuleChain; |
37 | 37 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
38 | 38 | import org.thingsboard.server.common.data.rule.RuleNode; |
... | ... | @@ -147,7 +147,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac |
147 | 147 | |
148 | 148 | Thread.sleep(3000); |
149 | 149 | |
150 | - TimePageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); | |
150 | + PageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); | |
151 | 151 | List<Event> events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); |
152 | 152 | |
153 | 153 | Assert.assertEquals(2, events.size()); | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
26 | 26 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
27 | 27 | import org.thingsboard.server.common.data.id.EntityId; |
28 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | -import org.thingsboard.server.common.data.page.TimePageData; | |
29 | +import org.thingsboard.server.common.data.page.PageData; | |
30 | 30 | |
31 | 31 | /** |
32 | 32 | * Created by ashvayka on 11.05.17. |
... | ... | @@ -45,7 +45,7 @@ public interface AlarmService { |
45 | 45 | |
46 | 46 | ListenableFuture<AlarmInfo> findAlarmInfoByIdAsync(TenantId tenantId, AlarmId alarmId); |
47 | 47 | |
48 | - ListenableFuture<TimePageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query); | |
48 | + ListenableFuture<PageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query); | |
49 | 49 | |
50 | 50 | AlarmSeverity findHighestAlarmSeverity(TenantId tenantId, EntityId entityId, AlarmSearchStatus alarmSearchStatus, |
51 | 51 | AlarmStatus alarmStatus); | ... | ... |
... | ... | @@ -18,18 +18,21 @@ package org.thingsboard.server.dao.asset; |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.EntitySubtype; |
20 | 20 | import org.thingsboard.server.common.data.asset.Asset; |
21 | +import org.thingsboard.server.common.data.asset.AssetInfo; | |
21 | 22 | import org.thingsboard.server.common.data.asset.AssetSearchQuery; |
22 | 23 | import org.thingsboard.server.common.data.id.AssetId; |
23 | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
24 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
25 | -import org.thingsboard.server.common.data.page.TextPageData; | |
26 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
26 | +import org.thingsboard.server.common.data.page.PageData; | |
27 | +import org.thingsboard.server.common.data.page.PageLink; | |
27 | 28 | |
28 | 29 | import java.util.List; |
29 | 30 | import java.util.Optional; |
30 | 31 | |
31 | 32 | public interface AssetService { |
32 | 33 | |
34 | + AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId); | |
35 | + | |
33 | 36 | Asset findAssetById(TenantId tenantId, AssetId assetId); |
34 | 37 | |
35 | 38 | ListenableFuture<Asset> findAssetByIdAsync(TenantId tenantId, AssetId assetId); |
... | ... | @@ -44,17 +47,25 @@ public interface AssetService { |
44 | 47 | |
45 | 48 | void deleteAsset(TenantId tenantId, AssetId assetId); |
46 | 49 | |
47 | - TextPageData<Asset> findAssetsByTenantId(TenantId tenantId, TextPageLink pageLink); | |
50 | + PageData<Asset> findAssetsByTenantId(TenantId tenantId, PageLink pageLink); | |
51 | + | |
52 | + PageData<AssetInfo> findAssetInfosByTenantId(TenantId tenantId, PageLink pageLink); | |
53 | + | |
54 | + PageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | |
48 | 55 | |
49 | - TextPageData<Asset> findAssetsByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink); | |
56 | + PageData<AssetInfo> findAssetInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | |
50 | 57 | |
51 | 58 | ListenableFuture<List<Asset>> findAssetsByTenantIdAndIdsAsync(TenantId tenantId, List<AssetId> assetIds); |
52 | 59 | |
53 | 60 | void deleteAssetsByTenantId(TenantId tenantId); |
54 | 61 | |
55 | - TextPageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); | |
62 | + PageData<Asset> findAssetsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
63 | + | |
64 | + PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
65 | + | |
66 | + PageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink); | |
56 | 67 | |
57 | - TextPageData<Asset> findAssetsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink); | |
68 | + PageData<AssetInfo> findAssetInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink); | |
58 | 69 | |
59 | 70 | ListenableFuture<List<Asset>> findAssetsByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<AssetId> assetIds); |
60 | 71 | ... | ... |
... | ... | @@ -25,20 +25,20 @@ import org.thingsboard.server.common.data.id.EntityId; |
25 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
26 | 26 | import org.thingsboard.server.common.data.id.UUIDBased; |
27 | 27 | import org.thingsboard.server.common.data.id.UserId; |
28 | -import org.thingsboard.server.common.data.page.TimePageData; | |
28 | +import org.thingsboard.server.common.data.page.PageData; | |
29 | 29 | import org.thingsboard.server.common.data.page.TimePageLink; |
30 | 30 | |
31 | 31 | import java.util.List; |
32 | 32 | |
33 | 33 | public interface AuditLogService { |
34 | 34 | |
35 | - TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, List<ActionType> actionTypes, TimePageLink pageLink); | |
35 | + PageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, List<ActionType> actionTypes, TimePageLink pageLink); | |
36 | 36 | |
37 | - TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, List<ActionType> actionTypes, TimePageLink pageLink); | |
37 | + PageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, List<ActionType> actionTypes, TimePageLink pageLink); | |
38 | 38 | |
39 | - TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, List<ActionType> actionTypes, TimePageLink pageLink); | |
39 | + PageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, List<ActionType> actionTypes, TimePageLink pageLink); | |
40 | 40 | |
41 | - TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, List<ActionType> actionTypes, TimePageLink pageLink); | |
41 | + PageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, List<ActionType> actionTypes, TimePageLink pageLink); | |
42 | 42 | |
43 | 43 | <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> logEntityAction( |
44 | 44 | TenantId tenantId, | ... | ... |
... | ... | @@ -18,8 +18,8 @@ package org.thingsboard.server.dao.component; |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import org.thingsboard.server.common.data.id.ComponentDescriptorId; |
20 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
21 | -import org.thingsboard.server.common.data.page.TextPageData; | |
22 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
21 | +import org.thingsboard.server.common.data.page.PageData; | |
22 | +import org.thingsboard.server.common.data.page.PageLink; | |
23 | 23 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
24 | 24 | import org.thingsboard.server.common.data.plugin.ComponentScope; |
25 | 25 | import org.thingsboard.server.common.data.plugin.ComponentType; |
... | ... | @@ -35,9 +35,9 @@ public interface ComponentDescriptorService { |
35 | 35 | |
36 | 36 | ComponentDescriptor findByClazz(TenantId tenantId, String clazz); |
37 | 37 | |
38 | - TextPageData<ComponentDescriptor> findByTypeAndPageLink(TenantId tenantId, ComponentType type, TextPageLink pageLink); | |
38 | + PageData<ComponentDescriptor> findByTypeAndPageLink(TenantId tenantId, ComponentType type, PageLink pageLink); | |
39 | 39 | |
40 | - TextPageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(TenantId tenantId, ComponentScope scope, ComponentType type, TextPageLink pageLink); | |
40 | + PageData<ComponentDescriptor> findByScopeAndTypeAndPageLink(TenantId tenantId, ComponentScope scope, ComponentType type, PageLink pageLink); | |
41 | 41 | |
42 | 42 | boolean validate(TenantId tenantId, ComponentDescriptor component, JsonNode configuration); |
43 | 43 | ... | ... |
... | ... | @@ -19,8 +19,8 @@ import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.Customer; |
20 | 20 | import org.thingsboard.server.common.data.id.CustomerId; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | -import org.thingsboard.server.common.data.page.TextPageData; | |
23 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
22 | +import org.thingsboard.server.common.data.page.PageData; | |
23 | +import org.thingsboard.server.common.data.page.PageLink; | |
24 | 24 | |
25 | 25 | import java.util.Optional; |
26 | 26 | |
... | ... | @@ -38,7 +38,7 @@ public interface CustomerService { |
38 | 38 | |
39 | 39 | Customer findOrCreatePublicCustomer(TenantId tenantId); |
40 | 40 | |
41 | - TextPageData<Customer> findCustomersByTenantId(TenantId tenantId, TextPageLink pageLink); | |
41 | + PageData<Customer> findCustomersByTenantId(TenantId tenantId, PageLink pageLink); | |
42 | 42 | |
43 | 43 | void deleteCustomersByTenantId(TenantId tenantId); |
44 | 44 | ... | ... |
... | ... | @@ -21,9 +21,8 @@ import org.thingsboard.server.common.data.DashboardInfo; |
21 | 21 | import org.thingsboard.server.common.data.id.CustomerId; |
22 | 22 | import org.thingsboard.server.common.data.id.DashboardId; |
23 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | -import org.thingsboard.server.common.data.page.TextPageData; | |
25 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
26 | -import org.thingsboard.server.common.data.page.TimePageData; | |
24 | +import org.thingsboard.server.common.data.page.PageData; | |
25 | +import org.thingsboard.server.common.data.page.PageLink; | |
27 | 26 | import org.thingsboard.server.common.data.page.TimePageLink; |
28 | 27 | |
29 | 28 | public interface DashboardService { |
... | ... | @@ -44,11 +43,11 @@ public interface DashboardService { |
44 | 43 | |
45 | 44 | void deleteDashboard(TenantId tenantId, DashboardId dashboardId); |
46 | 45 | |
47 | - TextPageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, TextPageLink pageLink); | |
46 | + PageData<DashboardInfo> findDashboardsByTenantId(TenantId tenantId, PageLink pageLink); | |
48 | 47 | |
49 | 48 | void deleteDashboardsByTenantId(TenantId tenantId); |
50 | 49 | |
51 | - ListenableFuture<TimePageData<DashboardInfo>> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink); | |
50 | + PageData<DashboardInfo> findDashboardsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
52 | 51 | |
53 | 52 | void unassignCustomerDashboards(TenantId tenantId, CustomerId customerId); |
54 | 53 | ... | ... |
... | ... | @@ -17,18 +17,21 @@ package org.thingsboard.server.dao.device; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.Device; |
20 | +import org.thingsboard.server.common.data.DeviceInfo; | |
20 | 21 | import org.thingsboard.server.common.data.EntitySubtype; |
21 | 22 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
22 | 23 | import org.thingsboard.server.common.data.id.CustomerId; |
23 | 24 | import org.thingsboard.server.common.data.id.DeviceId; |
24 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
25 | -import org.thingsboard.server.common.data.page.TextPageData; | |
26 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
26 | +import org.thingsboard.server.common.data.page.PageData; | |
27 | +import org.thingsboard.server.common.data.page.PageLink; | |
27 | 28 | |
28 | 29 | import java.util.List; |
29 | 30 | |
30 | 31 | public interface DeviceService { |
31 | - | |
32 | + | |
33 | + DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId); | |
34 | + | |
32 | 35 | Device findDeviceById(TenantId tenantId, DeviceId deviceId); |
33 | 36 | |
34 | 37 | ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId); |
... | ... | @@ -45,17 +48,25 @@ public interface DeviceService { |
45 | 48 | |
46 | 49 | void deleteDevice(TenantId tenantId, DeviceId deviceId); |
47 | 50 | |
48 | - TextPageData<Device> findDevicesByTenantId(TenantId tenantId, TextPageLink pageLink); | |
51 | + PageData<Device> findDevicesByTenantId(TenantId tenantId, PageLink pageLink); | |
52 | + | |
53 | + PageData<DeviceInfo> findDeviceInfosByTenantId(TenantId tenantId, PageLink pageLink); | |
49 | 54 | |
50 | - TextPageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, TextPageLink pageLink); | |
55 | + PageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | |
56 | + | |
57 | + PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | |
51 | 58 | |
52 | 59 | ListenableFuture<List<Device>> findDevicesByTenantIdAndIdsAsync(TenantId tenantId, List<DeviceId> deviceIds); |
53 | 60 | |
54 | 61 | void deleteDevicesByTenantId(TenantId tenantId); |
55 | 62 | |
56 | - TextPageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); | |
63 | + PageData<Device> findDevicesByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
64 | + | |
65 | + PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
66 | + | |
67 | + PageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink); | |
57 | 68 | |
58 | - TextPageData<Device> findDevicesByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, TextPageLink pageLink); | |
69 | + PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink); | |
59 | 70 | |
60 | 71 | ListenableFuture<List<Device>> findDevicesByTenantIdCustomerIdAndIdsAsync(TenantId tenantId, CustomerId customerId, List<DeviceId> deviceIds); |
61 | 72 | ... | ... |
... | ... | @@ -18,14 +18,15 @@ package org.thingsboard.server.dao.entityview; |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.EntitySubtype; |
20 | 20 | import org.thingsboard.server.common.data.EntityView; |
21 | +import org.thingsboard.server.common.data.EntityViewInfo; | |
21 | 22 | import org.thingsboard.server.common.data.Tenant; |
22 | 23 | import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; |
23 | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
24 | 25 | import org.thingsboard.server.common.data.id.EntityId; |
25 | 26 | import org.thingsboard.server.common.data.id.EntityViewId; |
26 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | -import org.thingsboard.server.common.data.page.TextPageData; | |
28 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
28 | +import org.thingsboard.server.common.data.page.PageData; | |
29 | +import org.thingsboard.server.common.data.page.PageLink; | |
29 | 30 | |
30 | 31 | import java.util.List; |
31 | 32 | |
... | ... | @@ -42,17 +43,27 @@ public interface EntityViewService { |
42 | 43 | |
43 | 44 | void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); |
44 | 45 | |
46 | + EntityViewInfo findEntityViewInfoById(TenantId tenantId, EntityViewId entityViewId); | |
47 | + | |
45 | 48 | EntityView findEntityViewById(TenantId tenantId, EntityViewId entityViewId); |
46 | 49 | |
47 | 50 | EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name); |
48 | 51 | |
49 | - TextPageData<EntityView> findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); | |
52 | + PageData<EntityView> findEntityViewByTenantId(TenantId tenantId, PageLink pageLink); | |
53 | + | |
54 | + PageData<EntityViewInfo> findEntityViewInfosByTenantId(TenantId tenantId, PageLink pageLink); | |
55 | + | |
56 | + PageData<EntityView> findEntityViewByTenantIdAndType(TenantId tenantId, PageLink pageLink, String type); | |
57 | + | |
58 | + PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); | |
59 | + | |
60 | + PageData<EntityView> findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
50 | 61 | |
51 | - TextPageData<EntityView> findEntityViewByTenantIdAndType(TenantId tenantId, TextPageLink pageLink, String type); | |
62 | + PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
52 | 63 | |
53 | - TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); | |
64 | + PageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, PageLink pageLink, String type); | |
54 | 65 | |
55 | - TextPageData<EntityView> findEntityViewsByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, TextPageLink pageLink, String type); | |
66 | + PageData<EntityViewInfo> findEntityViewInfosByTenantIdAndCustomerIdAndType(TenantId tenantId, CustomerId customerId, String type, PageLink pageLink); | |
56 | 67 | |
57 | 68 | ListenableFuture<List<EntityView>> findEntityViewsByQuery(TenantId tenantId, EntityViewSearchQuery query); |
58 | 69 | ... | ... |
... | ... | @@ -19,7 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.Event; |
20 | 20 | import org.thingsboard.server.common.data.id.EntityId; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | -import org.thingsboard.server.common.data.page.TimePageData; | |
22 | +import org.thingsboard.server.common.data.page.PageData; | |
23 | 23 | import org.thingsboard.server.common.data.page.TimePageLink; |
24 | 24 | |
25 | 25 | import java.util.List; |
... | ... | @@ -35,9 +35,9 @@ public interface EventService { |
35 | 35 | |
36 | 36 | Optional<Event> findEvent(TenantId tenantId, EntityId entityId, String eventType, String eventUid); |
37 | 37 | |
38 | - TimePageData<Event> findEvents(TenantId tenantId, EntityId entityId, TimePageLink pageLink); | |
38 | + PageData<Event> findEvents(TenantId tenantId, EntityId entityId, TimePageLink pageLink); | |
39 | 39 | |
40 | - TimePageData<Event> findEvents(TenantId tenantId, EntityId entityId, String eventType, TimePageLink pageLink); | |
40 | + PageData<Event> findEvents(TenantId tenantId, EntityId entityId, String eventType, TimePageLink pageLink); | |
41 | 41 | |
42 | 42 | List<Event> findLatestEvents(TenantId tenantId, EntityId entityId, String eventType, int limit); |
43 | 43 | ... | ... |
... | ... | @@ -19,8 +19,8 @@ import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.id.RuleChainId; |
20 | 20 | import org.thingsboard.server.common.data.id.RuleNodeId; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | -import org.thingsboard.server.common.data.page.TextPageData; | |
23 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
22 | +import org.thingsboard.server.common.data.page.PageData; | |
23 | +import org.thingsboard.server.common.data.page.PageLink; | |
24 | 24 | import org.thingsboard.server.common.data.relation.EntityRelation; |
25 | 25 | import org.thingsboard.server.common.data.rule.RuleChain; |
26 | 26 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
... | ... | @@ -57,7 +57,7 @@ public interface RuleChainService { |
57 | 57 | |
58 | 58 | List<EntityRelation> getRuleNodeRelations(TenantId tenantId, RuleNodeId ruleNodeId); |
59 | 59 | |
60 | - TextPageData<RuleChain> findTenantRuleChains(TenantId tenantId, TextPageLink pageLink); | |
60 | + PageData<RuleChain> findTenantRuleChains(TenantId tenantId, PageLink pageLink); | |
61 | 61 | |
62 | 62 | void deleteRuleChainById(TenantId tenantId, RuleChainId ruleChainId); |
63 | 63 | ... | ... |
... | ... | @@ -18,8 +18,8 @@ package org.thingsboard.server.dao.tenant; |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.Tenant; |
20 | 20 | import org.thingsboard.server.common.data.id.TenantId; |
21 | -import org.thingsboard.server.common.data.page.TextPageData; | |
22 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
21 | +import org.thingsboard.server.common.data.page.PageData; | |
22 | +import org.thingsboard.server.common.data.page.PageLink; | |
23 | 23 | |
24 | 24 | public interface TenantService { |
25 | 25 | |
... | ... | @@ -31,7 +31,7 @@ public interface TenantService { |
31 | 31 | |
32 | 32 | void deleteTenant(TenantId tenantId); |
33 | 33 | |
34 | - TextPageData<Tenant> findTenants(TextPageLink pageLink); | |
34 | + PageData<Tenant> findTenants(PageLink pageLink); | |
35 | 35 | |
36 | 36 | void deleteTenants(); |
37 | 37 | } | ... | ... |
... | ... | @@ -21,8 +21,8 @@ import org.thingsboard.server.common.data.id.CustomerId; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | 22 | import org.thingsboard.server.common.data.id.UserCredentialsId; |
23 | 23 | import org.thingsboard.server.common.data.id.UserId; |
24 | -import org.thingsboard.server.common.data.page.TextPageData; | |
25 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
24 | +import org.thingsboard.server.common.data.page.PageData; | |
25 | +import org.thingsboard.server.common.data.page.PageLink; | |
26 | 26 | import org.thingsboard.server.common.data.security.UserCredentials; |
27 | 27 | |
28 | 28 | public interface UserService { |
... | ... | @@ -53,11 +53,11 @@ public interface UserService { |
53 | 53 | |
54 | 54 | void deleteUser(TenantId tenantId, UserId userId); |
55 | 55 | |
56 | - TextPageData<User> findTenantAdmins(TenantId tenantId, TextPageLink pageLink); | |
56 | + PageData<User> findTenantAdmins(TenantId tenantId, PageLink pageLink); | |
57 | 57 | |
58 | 58 | void deleteTenantAdmins(TenantId tenantId); |
59 | - | |
60 | - TextPageData<User> findCustomerUsers(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); | |
59 | + | |
60 | + PageData<User> findCustomerUsers(TenantId tenantId, CustomerId customerId, PageLink pageLink); | |
61 | 61 | |
62 | 62 | void deleteCustomerUsers(TenantId tenantId, CustomerId customerId); |
63 | 63 | ... | ... |
... | ... | @@ -17,6 +17,5 @@ package org.thingsboard.server.dao.util; |
17 | 17 | |
18 | 18 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
19 | 19 | |
20 | -@ConditionalOnProperty(prefix = "database.entities", value = "type", havingValue = "sql") | |
21 | 20 | public @interface SqlDao { |
22 | 21 | } | ... | ... |
... | ... | @@ -17,8 +17,8 @@ package org.thingsboard.server.dao.widget; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.id.TenantId; |
19 | 19 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
20 | -import org.thingsboard.server.common.data.page.TextPageData; | |
21 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
20 | +import org.thingsboard.server.common.data.page.PageData; | |
21 | +import org.thingsboard.server.common.data.page.PageLink; | |
22 | 22 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
23 | 23 | |
24 | 24 | import java.util.List; |
... | ... | @@ -33,13 +33,13 @@ public interface WidgetsBundleService { |
33 | 33 | |
34 | 34 | WidgetsBundle findWidgetsBundleByTenantIdAndAlias(TenantId tenantId, String alias); |
35 | 35 | |
36 | - TextPageData<WidgetsBundle> findSystemWidgetsBundlesByPageLink(TenantId tenantId, TextPageLink pageLink); | |
36 | + PageData<WidgetsBundle> findSystemWidgetsBundlesByPageLink(TenantId tenantId, PageLink pageLink); | |
37 | 37 | |
38 | 38 | List<WidgetsBundle> findSystemWidgetsBundles(TenantId tenantId); |
39 | 39 | |
40 | - TextPageData<WidgetsBundle> findTenantWidgetsBundlesByTenantId(TenantId tenantId, TextPageLink pageLink); | |
40 | + PageData<WidgetsBundle> findTenantWidgetsBundlesByTenantId(TenantId tenantId, PageLink pageLink); | |
41 | 41 | |
42 | - TextPageData<WidgetsBundle> findAllTenantWidgetsBundlesByTenantIdAndPageLink(TenantId tenantId, TextPageLink pageLink); | |
42 | + PageData<WidgetsBundle> findAllTenantWidgetsBundlesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink); | |
43 | 43 | |
44 | 44 | List<WidgetsBundle> findAllTenantWidgetsBundlesByTenantId(TenantId tenantId); |
45 | 45 | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.DeviceId; | |
20 | + | |
21 | +@Data | |
22 | +public class DeviceInfo extends Device { | |
23 | + | |
24 | + private String customerTitle; | |
25 | + private boolean customerIsPublic; | |
26 | + | |
27 | + public DeviceInfo() { | |
28 | + super(); | |
29 | + } | |
30 | + | |
31 | + public DeviceInfo(DeviceId deviceId) { | |
32 | + super(deviceId); | |
33 | + } | |
34 | + | |
35 | + public DeviceInfo(Device device, String customerTitle, boolean customerIsPublic) { | |
36 | + super(device); | |
37 | + this.customerTitle = customerTitle; | |
38 | + this.customerIsPublic = customerIsPublic; | |
39 | + } | |
40 | +} | ... | ... |
... | ... | @@ -55,6 +55,14 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> |
55 | 55 | |
56 | 56 | public EntityView(EntityView entityView) { |
57 | 57 | super(entityView); |
58 | + this.entityId = entityView.getEntityId(); | |
59 | + this.tenantId = entityView.getTenantId(); | |
60 | + this.customerId = entityView.getCustomerId(); | |
61 | + this.name = entityView.getName(); | |
62 | + this.type = entityView.getType(); | |
63 | + this.keys = entityView.getKeys(); | |
64 | + this.startTimeMs = entityView.getStartTimeMs(); | |
65 | + this.endTimeMs = entityView.getEndTimeMs(); | |
58 | 66 | } |
59 | 67 | |
60 | 68 | @Override | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.EntityViewId; | |
20 | + | |
21 | +@Data | |
22 | +public class EntityViewInfo extends EntityView { | |
23 | + | |
24 | + private String customerTitle; | |
25 | + private boolean customerIsPublic; | |
26 | + | |
27 | + public EntityViewInfo() { | |
28 | + super(); | |
29 | + } | |
30 | + | |
31 | + public EntityViewInfo(EntityViewId entityViewId) { | |
32 | + super(entityViewId); | |
33 | + } | |
34 | + | |
35 | + public EntityViewInfo(EntityView entityView, String customerTitle, boolean customerIsPublic) { | |
36 | + super(entityView); | |
37 | + this.customerTitle = customerTitle; | |
38 | + this.customerIsPublic = customerIsPublic; | |
39 | + } | |
40 | +} | ... | ... |
... | ... | @@ -29,6 +29,11 @@ public class AlarmInfo extends Alarm { |
29 | 29 | super(alarm); |
30 | 30 | } |
31 | 31 | |
32 | + public AlarmInfo(Alarm alarm, String originatorName) { | |
33 | + super(alarm); | |
34 | + this.originatorName = originatorName; | |
35 | + } | |
36 | + | |
32 | 37 | public String getOriginatorName() { |
33 | 38 | return originatorName; |
34 | 39 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.asset; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.AssetId; | |
20 | + | |
21 | +@Data | |
22 | +public class AssetInfo extends Asset { | |
23 | + | |
24 | + private String customerTitle; | |
25 | + private boolean customerIsPublic; | |
26 | + | |
27 | + public AssetInfo() { | |
28 | + super(); | |
29 | + } | |
30 | + | |
31 | + public AssetInfo(AssetId assetId) { | |
32 | + super(assetId); | |
33 | + } | |
34 | + | |
35 | + public AssetInfo(Asset asset, String customerTitle, boolean customerIsPublic) { | |
36 | + super(asset); | |
37 | + this.customerTitle = customerTitle; | |
38 | + this.customerIsPublic = customerIsPublic; | |
39 | + } | |
40 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/page/PageData.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/page/TimePageData.java
... | ... | @@ -18,39 +18,29 @@ package org.thingsboard.server.common.data.page; |
18 | 18 | import com.fasterxml.jackson.annotation.JsonCreator; |
19 | 19 | import com.fasterxml.jackson.annotation.JsonProperty; |
20 | 20 | import org.thingsboard.server.common.data.BaseData; |
21 | -import org.thingsboard.server.common.data.SearchTextBased; | |
22 | -import org.thingsboard.server.common.data.id.UUIDBased; | |
23 | 21 | |
22 | +import java.util.Collections; | |
24 | 23 | import java.util.List; |
25 | -import java.util.UUID; | |
26 | 24 | |
27 | -public class TimePageData<T extends BaseData<? extends UUIDBased>> { | |
25 | +public class PageData<T> { | |
28 | 26 | |
29 | 27 | private final List<T> data; |
30 | - private final TimePageLink nextPageLink; | |
28 | + private final int totalPages; | |
29 | + private final long totalElements; | |
31 | 30 | private final boolean hasNext; |
32 | 31 | |
33 | - public TimePageData(List<T> data, TimePageLink pageLink) { | |
34 | - super(); | |
35 | - this.data = data; | |
36 | - int limit = pageLink.getLimit(); | |
37 | - if (data != null && data.size() == limit) { | |
38 | - int index = data.size() - 1; | |
39 | - UUID idOffset = data.get(index).getId().getId(); | |
40 | - nextPageLink = new TimePageLink(limit, pageLink.getStartTime(), pageLink.getEndTime(), pageLink.isAscOrder(), idOffset); | |
41 | - hasNext = true; | |
42 | - } else { | |
43 | - nextPageLink = null; | |
44 | - hasNext = false; | |
45 | - } | |
32 | + public PageData() { | |
33 | + this(Collections.emptyList(), 0, 0, false); | |
46 | 34 | } |
47 | 35 | |
48 | 36 | @JsonCreator |
49 | - public TimePageData(@JsonProperty("data") List<T> data, | |
50 | - @JsonProperty("nextPageLink") TimePageLink nextPageLink, | |
51 | - @JsonProperty("hasNext") boolean hasNext) { | |
37 | + public PageData(@JsonProperty("data") List<T> data, | |
38 | + @JsonProperty("totalPages") int totalPages, | |
39 | + @JsonProperty("totalElements") long totalElements, | |
40 | + @JsonProperty("hasNext") boolean hasNext) { | |
52 | 41 | this.data = data; |
53 | - this.nextPageLink = nextPageLink; | |
42 | + this.totalPages = totalPages; | |
43 | + this.totalElements = totalElements; | |
54 | 44 | this.hasNext = hasNext; |
55 | 45 | } |
56 | 46 | |
... | ... | @@ -58,13 +48,17 @@ public class TimePageData<T extends BaseData<? extends UUIDBased>> { |
58 | 48 | return data; |
59 | 49 | } |
60 | 50 | |
51 | + public int getTotalPages() { | |
52 | + return totalPages; | |
53 | + } | |
54 | + | |
55 | + public long getTotalElements() { | |
56 | + return totalElements; | |
57 | + } | |
58 | + | |
61 | 59 | @JsonProperty("hasNext") |
62 | 60 | public boolean hasNext() { |
63 | 61 | return hasNext; |
64 | 62 | } |
65 | 63 | |
66 | - public TimePageLink getNextPageLink() { | |
67 | - return nextPageLink; | |
68 | - } | |
69 | - | |
70 | 64 | } | ... | ... |
... | ... | @@ -19,11 +19,12 @@ import java.util.Iterator; |
19 | 19 | import java.util.List; |
20 | 20 | import java.util.NoSuchElementException; |
21 | 21 | |
22 | +import org.thingsboard.server.common.data.BaseData; | |
22 | 23 | import org.thingsboard.server.common.data.SearchTextBased; |
23 | 24 | import org.thingsboard.server.common.data.id.EntityId; |
24 | 25 | import org.thingsboard.server.common.data.id.UUIDBased; |
25 | 26 | |
26 | -public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> implements Iterable<T>, Iterator<T> { | |
27 | +public class PageDataIterable<T> implements Iterable<T>, Iterator<T> { | |
27 | 28 | |
28 | 29 | private final FetchFunction<T> function; |
29 | 30 | private final int fetchSize; |
... | ... | @@ -31,7 +32,7 @@ public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> im |
31 | 32 | private List<T> currentItems; |
32 | 33 | private int currentIdx; |
33 | 34 | private boolean hasNextPack; |
34 | - private TextPageLink nextPackLink; | |
35 | + private PageLink nextPackLink; | |
35 | 36 | private boolean initialized; |
36 | 37 | |
37 | 38 | public PageDataIterable(FetchFunction<T> function, int fetchSize) { |
... | ... | @@ -48,7 +49,7 @@ public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> im |
48 | 49 | @Override |
49 | 50 | public boolean hasNext() { |
50 | 51 | if(!initialized){ |
51 | - fetch(new TextPageLink(fetchSize)); | |
52 | + fetch(new PageLink(fetchSize)); | |
52 | 53 | initialized = true; |
53 | 54 | } |
54 | 55 | if(currentIdx == currentItems.size()){ |
... | ... | @@ -59,12 +60,12 @@ public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> im |
59 | 60 | return currentIdx < currentItems.size(); |
60 | 61 | } |
61 | 62 | |
62 | - private void fetch(TextPageLink link) { | |
63 | - TextPageData<T> pageData = function.fetch(link); | |
63 | + private void fetch(PageLink link) { | |
64 | + PageData<T> pageData = function.fetch(link); | |
64 | 65 | currentIdx = 0; |
65 | 66 | currentItems = pageData.getData(); |
66 | 67 | hasNextPack = pageData.hasNext(); |
67 | - nextPackLink = pageData.getNextPageLink(); | |
68 | + nextPackLink = link.nextPageLink(); | |
68 | 69 | } |
69 | 70 | |
70 | 71 | @Override |
... | ... | @@ -75,9 +76,9 @@ public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> im |
75 | 76 | return currentItems.get(currentIdx++); |
76 | 77 | } |
77 | 78 | |
78 | - public static interface FetchFunction<T extends SearchTextBased<? extends UUIDBased>> { | |
79 | + public static interface FetchFunction<T> { | |
79 | 80 | |
80 | - TextPageData<T> fetch(TextPageLink link); | |
81 | + PageData<T> fetch(PageLink link); | |
81 | 82 | |
82 | 83 | } |
83 | 84 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.page; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | +import lombok.Data; | |
20 | + | |
21 | +@Data | |
22 | +public class PageLink { | |
23 | + | |
24 | + private final String textSearch; | |
25 | + private final int pageSize; | |
26 | + private final int page; | |
27 | + private final SortOrder sortOrder; | |
28 | + | |
29 | + public PageLink(PageLink pageLink) { | |
30 | + this.pageSize = pageLink.getPageSize(); | |
31 | + this.page = pageLink.getPage(); | |
32 | + this.textSearch = pageLink.getTextSearch(); | |
33 | + this.sortOrder = pageLink.getSortOrder(); | |
34 | + } | |
35 | + | |
36 | + public PageLink(int pageSize) { | |
37 | + this(pageSize, 0); | |
38 | + } | |
39 | + | |
40 | + public PageLink(int pageSize, int page) { | |
41 | + this(pageSize, page, null, null); | |
42 | + } | |
43 | + | |
44 | + public PageLink(int pageSize, int page, String textSearch) { | |
45 | + this(pageSize, page, textSearch, null); | |
46 | + } | |
47 | + | |
48 | + public PageLink(int pageSize, int page, String textSearch, SortOrder sortOrder) { | |
49 | + this.pageSize = pageSize; | |
50 | + this.page = page; | |
51 | + this.textSearch = textSearch; | |
52 | + this.sortOrder = sortOrder; | |
53 | + } | |
54 | + | |
55 | + @JsonIgnore | |
56 | + public PageLink nextPageLink() { | |
57 | + return new PageLink(this.pageSize, this.page+1, this.textSearch, this.sortOrder); | |
58 | + } | |
59 | + | |
60 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2020 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.page; | |
17 | + | |
18 | +import lombok.Data; | |
19 | + | |
20 | +@Data | |
21 | +public class SortOrder { | |
22 | + | |
23 | + private final String property; | |
24 | + private final Direction direction; | |
25 | + | |
26 | + public SortOrder(String property) { | |
27 | + this(property, Direction.ASC); | |
28 | + } | |
29 | + | |
30 | + public SortOrder(String property, Direction direction) { | |
31 | + this.property = property; | |
32 | + this.direction = direction; | |
33 | + } | |
34 | + | |
35 | + public static enum Direction { | |
36 | + ASC, DESC | |
37 | + } | |
38 | + | |
39 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/page/TextPageData.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.common.data.page; | |
17 | - | |
18 | -import java.util.List; | |
19 | -import java.util.UUID; | |
20 | - | |
21 | -import org.thingsboard.server.common.data.SearchTextBased; | |
22 | -import org.thingsboard.server.common.data.id.UUIDBased; | |
23 | - | |
24 | -import com.fasterxml.jackson.annotation.JsonCreator; | |
25 | -import com.fasterxml.jackson.annotation.JsonProperty; | |
26 | - | |
27 | -public class TextPageData<T extends SearchTextBased<? extends UUIDBased>> { | |
28 | - | |
29 | - private final List<T> data; | |
30 | - private final TextPageLink nextPageLink; | |
31 | - private final boolean hasNext; | |
32 | - | |
33 | - public TextPageData(List<T> data, TextPageLink pageLink) { | |
34 | - super(); | |
35 | - this.data = data; | |
36 | - int limit = pageLink.getLimit(); | |
37 | - if (data != null && data.size() == limit) { | |
38 | - int index = data.size()-1; | |
39 | - UUID idOffset = data.get(index).getId().getId(); | |
40 | - String textOffset = data.get(index).getSearchText(); | |
41 | - nextPageLink = new TextPageLink(limit, pageLink.getTextSearch(), idOffset, textOffset); | |
42 | - hasNext = true; | |
43 | - } else { | |
44 | - nextPageLink = null; | |
45 | - hasNext = false; | |
46 | - } | |
47 | - } | |
48 | - | |
49 | - @JsonCreator | |
50 | - public TextPageData(@JsonProperty("data") List<T> data, | |
51 | - @JsonProperty("nextPageLink") TextPageLink nextPageLink, | |
52 | - @JsonProperty("hasNext") boolean hasNext) { | |
53 | - this.data = data; | |
54 | - this.nextPageLink = nextPageLink; | |
55 | - this.hasNext = hasNext; | |
56 | - } | |
57 | - | |
58 | - public List<T> getData() { | |
59 | - return data; | |
60 | - } | |
61 | - | |
62 | - @JsonProperty("hasNext") | |
63 | - public boolean hasNext() { | |
64 | - return hasNext; | |
65 | - } | |
66 | - | |
67 | - public TextPageLink getNextPageLink() { | |
68 | - return nextPageLink; | |
69 | - } | |
70 | - | |
71 | -} |
common/data/src/main/java/org/thingsboard/server/common/data/page/TextPageLink.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.common.data.page; | |
17 | - | |
18 | -import com.fasterxml.jackson.annotation.JsonCreator; | |
19 | -import com.fasterxml.jackson.annotation.JsonProperty; | |
20 | -import lombok.Getter; | |
21 | -import lombok.ToString; | |
22 | - | |
23 | -import java.io.Serializable; | |
24 | -import java.util.Arrays; | |
25 | -import java.util.UUID; | |
26 | - | |
27 | -@ToString | |
28 | -public class TextPageLink extends BasePageLink implements Serializable { | |
29 | - | |
30 | - private static final long serialVersionUID = -4189954843653250480L; | |
31 | - | |
32 | - @Getter private final String textSearch; | |
33 | - @Getter private final String textSearchBound; | |
34 | - @Getter private final String textOffset; | |
35 | - | |
36 | - public TextPageLink(int limit) { | |
37 | - this(limit, null, null, null); | |
38 | - } | |
39 | - | |
40 | - public TextPageLink(int limit, String textSearch) { | |
41 | - this(limit, textSearch, null, null); | |
42 | - } | |
43 | - | |
44 | - public TextPageLink(int limit, String textSearch, UUID idOffset, String textOffset) { | |
45 | - super(limit, idOffset); | |
46 | - this.textSearch = textSearch != null ? textSearch.toLowerCase() : null; | |
47 | - this.textSearchBound = nextSequence(this.textSearch); | |
48 | - this.textOffset = textOffset != null ? textOffset.toLowerCase() : null; | |
49 | - } | |
50 | - | |
51 | - @JsonCreator | |
52 | - public TextPageLink(@JsonProperty("limit") int limit, | |
53 | - @JsonProperty("textSearch") String textSearch, | |
54 | - @JsonProperty("textSearchBound") String textSearchBound, | |
55 | - @JsonProperty("textOffset") String textOffset, | |
56 | - @JsonProperty("idOffset") UUID idOffset) { | |
57 | - super(limit, idOffset); | |
58 | - this.textSearch = textSearch; | |
59 | - this.textSearchBound = textSearchBound; | |
60 | - this.textOffset = textOffset; | |
61 | - this.idOffset = idOffset; | |
62 | - } | |
63 | - | |
64 | - private static String nextSequence(String input) { | |
65 | - if (input != null && input.length() > 0) { | |
66 | - char[] chars = input.toCharArray(); | |
67 | - int i = chars.length - 1; | |
68 | - while (i >= 0 && ++chars[i--] == Character.MIN_VALUE) ; | |
69 | - if (i == -1 && (chars.length == 0 || chars[0] == Character.MIN_VALUE)) { | |
70 | - char buf[] = Arrays.copyOf(input.toCharArray(), input.length() + 1); | |
71 | - buf[buf.length - 1] = Character.MIN_VALUE; | |
72 | - return new String(buf); | |
73 | - } | |
74 | - return new String(chars); | |
75 | - } else { | |
76 | - return null; | |
77 | - } | |
78 | - } | |
79 | - | |
80 | -} |
... | ... | @@ -16,7 +16,9 @@ |
16 | 16 | package org.thingsboard.server.common.data.page; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonCreator; |
19 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | 20 | import com.fasterxml.jackson.annotation.JsonProperty; |
21 | +import lombok.Data; | |
20 | 22 | import lombok.Getter; |
21 | 23 | import lombok.ToString; |
22 | 24 | |
... | ... | @@ -24,40 +26,43 @@ import java.io.Serializable; |
24 | 26 | import java.util.Arrays; |
25 | 27 | import java.util.UUID; |
26 | 28 | |
27 | -@ToString | |
28 | -public class TimePageLink extends BasePageLink implements Serializable { | |
29 | +@Data | |
30 | +public class TimePageLink extends PageLink { | |
29 | 31 | |
30 | - private static final long serialVersionUID = -4189954843653250480L; | |
32 | + private final Long startTime; | |
33 | + private final Long endTime; | |
31 | 34 | |
32 | - @Getter private final Long startTime; | |
33 | - @Getter private final Long endTime; | |
34 | - @Getter private final boolean ascOrder; | |
35 | + public TimePageLink(PageLink pageLink, Long startTime, Long endTime) { | |
36 | + super(pageLink); | |
37 | + this.startTime = startTime; | |
38 | + this.endTime = endTime; | |
39 | + } | |
35 | 40 | |
36 | - public TimePageLink(int limit) { | |
37 | - this(limit, null, null, false, null); | |
41 | + public TimePageLink(int pageSize) { | |
42 | + this(pageSize, 0); | |
38 | 43 | } |
39 | 44 | |
40 | - public TimePageLink(int limit, Long startTime) { | |
41 | - this(limit, startTime, null, false, null); | |
45 | + public TimePageLink(int pageSize, int page) { | |
46 | + this(pageSize, page, null); | |
42 | 47 | } |
43 | 48 | |
44 | - public TimePageLink(int limit, Long startTime, Long endTime) { | |
45 | - this(limit, startTime, endTime, false, null); | |
49 | + public TimePageLink(int pageSize, int page, String textSearch) { | |
50 | + this(pageSize, page, textSearch, null, null, null); | |
46 | 51 | } |
47 | 52 | |
48 | - public TimePageLink(int limit, Long startTime, Long endTime, boolean ascOrder) { | |
49 | - this(limit, startTime, endTime, ascOrder, null); | |
53 | + public TimePageLink(int pageSize, int page, String textSearch, SortOrder sortOrder) { | |
54 | + this(pageSize, page, textSearch, sortOrder, null, null); | |
50 | 55 | } |
51 | 56 | |
52 | - @JsonCreator | |
53 | - public TimePageLink(@JsonProperty("limit") int limit, | |
54 | - @JsonProperty("startTime") Long startTime, | |
55 | - @JsonProperty("endTime") Long endTime, | |
56 | - @JsonProperty("ascOrder") boolean ascOrder, | |
57 | - @JsonProperty("idOffset") UUID idOffset) { | |
58 | - super(limit, idOffset); | |
57 | + public TimePageLink(int pageSize, int page, String textSearch, SortOrder sortOrder, Long startTime, Long endTime) { | |
58 | + super(pageSize, page, textSearch, sortOrder); | |
59 | 59 | this.startTime = startTime; |
60 | 60 | this.endTime = endTime; |
61 | - this.ascOrder = ascOrder; | |
61 | + } | |
62 | + | |
63 | + @JsonIgnore | |
64 | + public TimePageLink nextPageLink() { | |
65 | + return new TimePageLink(this.getPageSize(), this.getPage()+1, this.getTextSearch(), this.getSortOrder(), | |
66 | + this.startTime, this.endTime); | |
62 | 67 | } |
63 | 68 | } | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>common</artifactId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>3.0.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>dao</artifactId> | ... | ... |
... | ... | @@ -15,7 +15,16 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.dao; |
17 | 17 | |
18 | +import com.datastax.driver.core.utils.UUIDs; | |
19 | +import org.springframework.data.domain.Page; | |
20 | +import org.springframework.data.domain.PageRequest; | |
21 | +import org.springframework.data.domain.Pageable; | |
22 | +import org.springframework.data.domain.Sort; | |
23 | +import org.thingsboard.server.common.data.UUIDConverter; | |
18 | 24 | import org.thingsboard.server.common.data.id.UUIDBased; |
25 | +import org.thingsboard.server.common.data.page.PageData; | |
26 | +import org.thingsboard.server.common.data.page.PageLink; | |
27 | +import org.thingsboard.server.common.data.page.SortOrder; | |
19 | 28 | import org.thingsboard.server.dao.model.ToData; |
20 | 29 | |
21 | 30 | import java.util.*; |
... | ... | @@ -25,6 +34,56 @@ public abstract class DaoUtil { |
25 | 34 | private DaoUtil() { |
26 | 35 | } |
27 | 36 | |
37 | + public static <T> PageData<T> toPageData(Page<? extends ToData<T>> page) { | |
38 | + List<T> data = convertDataList(page.getContent()); | |
39 | + return new PageData(data, page.getTotalPages(), page.getTotalElements(), page.hasNext()); | |
40 | + } | |
41 | + | |
42 | + public static Pageable toPageable(PageLink pageLink) { | |
43 | + return toPageable(pageLink, Collections.emptyMap()); | |
44 | + } | |
45 | + | |
46 | + public static Pageable toPageable(PageLink pageLink, Map<String,String> columnMap) { | |
47 | + return PageRequest.of(pageLink.getPage(), pageLink.getPageSize(), toSort(pageLink.getSortOrder(), columnMap)); | |
48 | + } | |
49 | + | |
50 | + public static String startTimeToId(Long startTime) { | |
51 | + if (startTime != null) { | |
52 | + UUID startOf = UUIDs.startOf(startTime); | |
53 | + return UUIDConverter.fromTimeUUID(startOf); | |
54 | + } else { | |
55 | + return null; | |
56 | + } | |
57 | + } | |
58 | + | |
59 | + public static String endTimeToId(Long endTime) { | |
60 | + if (endTime != null) { | |
61 | + UUID endOf = UUIDs.endOf(endTime); | |
62 | + return UUIDConverter.fromTimeUUID(endOf); | |
63 | + } else { | |
64 | + return null; | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + public static Sort toSort(SortOrder sortOrder) { | |
69 | + return toSort(sortOrder, Collections.emptyMap()); | |
70 | + } | |
71 | + | |
72 | + public static Sort toSort(SortOrder sortOrder, Map<String,String> columnMap) { | |
73 | + if (sortOrder == null) { | |
74 | + return Sort.unsorted(); | |
75 | + } else { | |
76 | + String property = sortOrder.getProperty(); | |
77 | + if (columnMap.containsKey(property)) { | |
78 | + property = columnMap.get(property); | |
79 | + } | |
80 | + if (property.equals("createdTime")) { | |
81 | + property = "id"; | |
82 | + } | |
83 | + return Sort.by(Sort.Direction.fromString(sortOrder.getDirection().name()), property); | |
84 | + } | |
85 | + } | |
86 | + | |
28 | 87 | public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList) { |
29 | 88 | List<T> list = Collections.emptyList(); |
30 | 89 | if (toDataList != null && !toDataList.isEmpty()) { | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; |
21 | 21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
22 | 22 | import org.thingsboard.server.common.data.id.EntityId; |
23 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | +import org.thingsboard.server.common.data.page.PageData; | |
24 | 25 | import org.thingsboard.server.dao.Dao; |
25 | 26 | |
26 | 27 | import java.util.List; |
... | ... | @@ -39,5 +40,5 @@ public interface AlarmDao extends Dao<Alarm> { |
39 | 40 | |
40 | 41 | Alarm save(TenantId tenantId, Alarm alarm); |
41 | 42 | |
42 | - ListenableFuture<List<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query); | |
43 | + PageData<AlarmInfo> findAlarms(TenantId tenantId, AlarmQuery query); | |
43 | 44 | } | ... | ... |
... | ... | @@ -36,7 +36,7 @@ import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
36 | 36 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
37 | 37 | import org.thingsboard.server.common.data.id.EntityId; |
38 | 38 | import org.thingsboard.server.common.data.id.TenantId; |
39 | -import org.thingsboard.server.common.data.page.TimePageData; | |
39 | +import org.thingsboard.server.common.data.page.PageData; | |
40 | 40 | import org.thingsboard.server.common.data.page.TimePageLink; |
41 | 41 | import org.thingsboard.server.common.data.relation.EntityRelation; |
42 | 42 | import org.thingsboard.server.common.data.relation.EntityRelationsQuery; |
... | ... | @@ -270,32 +270,26 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
270 | 270 | } |
271 | 271 | |
272 | 272 | @Override |
273 | - public ListenableFuture<TimePageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) { | |
274 | - ListenableFuture<List<AlarmInfo>> alarms = alarmDao.findAlarms(tenantId, query); | |
273 | + public ListenableFuture<PageData<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) { | |
274 | + PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query); | |
275 | 275 | if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) { |
276 | - alarms = Futures.transformAsync(alarms, input -> { | |
277 | - List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(input.size()); | |
278 | - for (AlarmInfo alarmInfo : input) { | |
279 | - alarmFutures.add(Futures.transform( | |
280 | - entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { | |
281 | - if (originatorName == null) { | |
282 | - originatorName = "Deleted"; | |
283 | - } | |
284 | - alarmInfo.setOriginatorName(originatorName); | |
285 | - return alarmInfo; | |
276 | + List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(alarms.getData().size()); | |
277 | + for (AlarmInfo alarmInfo : alarms.getData()) { | |
278 | + alarmFutures.add(Futures.transform( | |
279 | + entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { | |
280 | + if (originatorName == null) { | |
281 | + originatorName = "Deleted"; | |
286 | 282 | } |
287 | - )); | |
288 | - } | |
289 | - return Futures.successfulAsList(alarmFutures); | |
283 | + alarmInfo.setOriginatorName(originatorName); | |
284 | + return alarmInfo; | |
285 | + } | |
286 | + )); | |
287 | + } | |
288 | + return Futures.transform(Futures.successfulAsList(alarmFutures), alarmInfos -> { | |
289 | + return new PageData(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(), alarms.hasNext()); | |
290 | 290 | }); |
291 | 291 | } |
292 | - return Futures.transform(alarms, new Function<List<AlarmInfo>, TimePageData<AlarmInfo>>() { | |
293 | - @Nullable | |
294 | - @Override | |
295 | - public TimePageData<AlarmInfo> apply(@Nullable List<AlarmInfo> alarms) { | |
296 | - return new TimePageData<>(alarms, query.getPageLink()); | |
297 | - } | |
298 | - }); | |
292 | + return Futures.immediateFuture(alarms); | |
299 | 293 | } |
300 | 294 | |
301 | 295 | @Override |
... | ... | @@ -307,19 +301,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
307 | 301 | AlarmQuery query; |
308 | 302 | while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) { |
309 | 303 | query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false); |
310 | - List<AlarmInfo> alarms; | |
311 | - try { | |
312 | - alarms = alarmDao.findAlarms(tenantId, query).get(); | |
313 | - } catch (ExecutionException | InterruptedException e) { | |
314 | - log.warn("Failed to find highest alarm severity. EntityId: [{}], AlarmSearchStatus: [{}], AlarmStatus: [{}]", | |
315 | - entityId, alarmSearchStatus, alarmStatus); | |
316 | - throw new RuntimeException(e); | |
317 | - } | |
318 | - hasNext = alarms.size() == nextPageLink.getLimit(); | |
319 | - if (hasNext) { | |
320 | - nextPageLink = new TimePageData<>(alarms, nextPageLink).getNextPageLink(); | |
304 | + PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query); | |
305 | + if (alarms.hasNext()) { | |
306 | + nextPageLink = nextPageLink.nextPageLink(); | |
321 | 307 | } |
322 | - AlarmSeverity severity = detectHighestSeverity(alarms); | |
308 | + AlarmSeverity severity = detectHighestSeverity(alarms.getData()); | |
323 | 309 | if (severity == null) { |
324 | 310 | continue; |
325 | 311 | } | ... | ... |
dao/src/main/java/org/thingsboard/server/dao/alarm/CassandraAlarmDao.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.dao.alarm; | |
17 | - | |
18 | -import com.datastax.driver.core.Statement; | |
19 | -import com.datastax.driver.core.querybuilder.QueryBuilder; | |
20 | -import com.datastax.driver.core.querybuilder.Select; | |
21 | -import com.google.common.util.concurrent.Futures; | |
22 | -import com.google.common.util.concurrent.ListenableFuture; | |
23 | -import lombok.extern.slf4j.Slf4j; | |
24 | -import org.springframework.beans.factory.annotation.Autowired; | |
25 | -import org.springframework.stereotype.Component; | |
26 | -import org.thingsboard.server.common.data.EntityType; | |
27 | -import org.thingsboard.server.common.data.alarm.Alarm; | |
28 | -import org.thingsboard.server.common.data.alarm.AlarmInfo; | |
29 | -import org.thingsboard.server.common.data.alarm.AlarmQuery; | |
30 | -import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | |
31 | -import org.thingsboard.server.common.data.id.EntityId; | |
32 | -import org.thingsboard.server.common.data.id.TenantId; | |
33 | -import org.thingsboard.server.common.data.relation.EntityRelation; | |
34 | -import org.thingsboard.server.common.data.relation.RelationTypeGroup; | |
35 | -import org.thingsboard.server.dao.model.ModelConstants; | |
36 | -import org.thingsboard.server.dao.model.nosql.AlarmEntity; | |
37 | -import org.thingsboard.server.dao.nosql.CassandraAbstractModelDao; | |
38 | -import org.thingsboard.server.dao.relation.RelationDao; | |
39 | -import org.thingsboard.server.dao.util.NoSqlDao; | |
40 | - | |
41 | -import java.util.ArrayList; | |
42 | -import java.util.List; | |
43 | -import java.util.UUID; | |
44 | - | |
45 | -import static com.datastax.driver.core.querybuilder.QueryBuilder.eq; | |
46 | -import static com.datastax.driver.core.querybuilder.QueryBuilder.select; | |
47 | -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_BY_ID_VIEW_NAME; | |
48 | -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_COLUMN_FAMILY_NAME; | |
49 | -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; | |
50 | -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; | |
51 | -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_TENANT_ID_PROPERTY; | |
52 | -import static org.thingsboard.server.dao.model.ModelConstants.ALARM_TYPE_PROPERTY; | |
53 | - | |
54 | -@Component | |
55 | -@Slf4j | |
56 | -@NoSqlDao | |
57 | -public class CassandraAlarmDao extends CassandraAbstractModelDao<AlarmEntity, Alarm> implements AlarmDao { | |
58 | - | |
59 | - @Autowired | |
60 | - private RelationDao relationDao; | |
61 | - | |
62 | - @Override | |
63 | - protected Class<AlarmEntity> getColumnFamilyClass() { | |
64 | - return AlarmEntity.class; | |
65 | - } | |
66 | - | |
67 | - @Override | |
68 | - protected String getColumnFamilyName() { | |
69 | - return ALARM_COLUMN_FAMILY_NAME; | |
70 | - } | |
71 | - | |
72 | - protected boolean isDeleteOnSave() { | |
73 | - return false; | |
74 | - } | |
75 | - | |
76 | - @Override | |
77 | - public Alarm save(TenantId tenantId, Alarm alarm) { | |
78 | - log.debug("Save asset [{}] ", alarm); | |
79 | - return super.save(tenantId, alarm); | |
80 | - } | |
81 | - | |
82 | - @Override | |
83 | - public Boolean deleteAlarm(TenantId tenantId, Alarm alarm) { | |
84 | - Statement delete = QueryBuilder.delete().all().from(getColumnFamilyName()).where(eq(ModelConstants.ID_PROPERTY, alarm.getId().getId())) | |
85 | - .and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId())) | |
86 | - .and(eq(ALARM_ORIGINATOR_ID_PROPERTY, alarm.getOriginator().getId())) | |
87 | - .and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, alarm.getOriginator().getEntityType())) | |
88 | - .and(eq(ALARM_TYPE_PROPERTY, alarm.getType())); | |
89 | - log.debug("Remove request: {}", delete.toString()); | |
90 | - return executeWrite(tenantId, delete).wasApplied(); | |
91 | - } | |
92 | - | |
93 | - @Override | |
94 | - public ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type) { | |
95 | - Select select = select().from(ALARM_COLUMN_FAMILY_NAME); | |
96 | - Select.Where query = select.where(); | |
97 | - query.and(eq(ALARM_TENANT_ID_PROPERTY, tenantId.getId())); | |
98 | - query.and(eq(ALARM_ORIGINATOR_ID_PROPERTY, originator.getId())); | |
99 | - query.and(eq(ALARM_ORIGINATOR_TYPE_PROPERTY, originator.getEntityType())); | |
100 | - query.and(eq(ALARM_TYPE_PROPERTY, type)); | |
101 | - query.limit(1); | |
102 | - query.orderBy(QueryBuilder.asc(ModelConstants.ALARM_TYPE_PROPERTY), QueryBuilder.desc(ModelConstants.ID_PROPERTY)); | |
103 | - return findOneByStatementAsync(tenantId, query); | |
104 | - } | |
105 | - | |
106 | - @Override | |
107 | - public ListenableFuture<List<AlarmInfo>> findAlarms(TenantId tenantId, AlarmQuery query) { | |
108 | - log.trace("Try to find alarms by entity [{}], searchStatus [{}], status [{}] and pageLink [{}]", query.getAffectedEntityId(), query.getSearchStatus(), query.getStatus(), query.getPageLink()); | |
109 | - EntityId affectedEntity = query.getAffectedEntityId(); | |
110 | - String searchStatusName; | |
111 | - if (query.getSearchStatus() == null && query.getStatus() == null) { | |
112 | - searchStatusName = AlarmSearchStatus.ANY.name(); | |
113 | - } else if (query.getSearchStatus() != null) { | |
114 | - searchStatusName = query.getSearchStatus().name(); | |
115 | - } else { | |
116 | - searchStatusName = query.getStatus().name(); | |
117 | - } | |
118 | - String relationType = BaseAlarmService.ALARM_RELATION_PREFIX + searchStatusName; | |
119 | - ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(tenantId, affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink()); | |
120 | - return Futures.transformAsync(relations, input -> { | |
121 | - List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(input.size()); | |
122 | - for (EntityRelation relation : input) { | |
123 | - alarmFutures.add(Futures.transform( | |
124 | - findAlarmByIdAsync(tenantId, relation.getTo().getId()), | |
125 | - AlarmInfo::new)); | |
126 | - } | |
127 | - return Futures.successfulAsList(alarmFutures); | |
128 | - }); | |
129 | - } | |
130 | - | |
131 | - @Override | |
132 | - public ListenableFuture<Alarm> findAlarmByIdAsync(TenantId tenantId, UUID key) { | |
133 | - log.debug("Get alarm by id {}", key); | |
134 | - Select.Where query = select().from(ALARM_BY_ID_VIEW_NAME).where(eq(ModelConstants.ID_PROPERTY, key)); | |
135 | - query.limit(1); | |
136 | - log.trace("Execute query {}", query); | |
137 | - return findOneByStatementAsync(tenantId, query); | |
138 | - } | |
139 | -} |