UI: Added conditionally show widget table cell button action

This commit is contained in:
Vladyslav_Prykhodko 2021-09-28 17:58:32 +03:00
parent 23121c5b5a
commit 814a685d76
13 changed files with 256 additions and 124 deletions

View File

@ -18,7 +18,7 @@
"resources": [],
"templateHtml": "<tb-alarms-table-widget \n [ctx]=\"ctx\">\n</tb-alarms-table-widget>",
"templateCss": "",
"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",
"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 hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n",
"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 \"enableFilter\": {\n \"title\": \"Enable alarm filter\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": false\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 \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(alarm, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"alarmsTitle\",\n \"enableSelection\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableFilter\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n \"displayDetails\",\n \"allowAcknowledgment\",\n \"allowClear\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}",
"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, alarm, ctx)\",\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, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}",
"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,\"enableStickyAction\":false,\"enableFilter\":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\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}"

View File

@ -54,7 +54,7 @@
"resources": [],
"templateHtml": "<tb-timeseries-table-widget \n [ctx]=\"ctx\">\n</tb-timeseries-table-widget>",
"templateCss": "",
"controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: 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}",
"controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}",
"settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"TimeseriesTableSettings\",\n \"properties\": {\n \"enableSearch\": {\n \"title\": \"Enable search\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\n \"type\": \"boolean\",\n \"default\": true\n },\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 \"useEntityLabel\": {\n \"title\": \"Use entity label in tab name\",\n \"type\": \"boolean\",\n \"default\": false\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 \"disableStickyHeader\": {\n \"title\": \"Disable sticky header\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(rowData, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableSearch\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n \"showTimestamp\",\n \"showMilliseconds\",\n \"displayPagination\",\n \"useEntityLabel\",\n \"defaultPageSize\",\n \"identifyDeviceSelector\",\n \"hideEmptyLines\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}",
"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, rowData, ctx)\",\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 \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n }\n ]\n}",
"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\"}"
@ -126,7 +126,7 @@
"resources": [],
"templateHtml": "<tb-entities-table-widget \n [ctx]=\"ctx\">\n</tb-entities-table-widget>",
"templateCss": "",
"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 hasDataPageLink: true,\n warnOnPageDataOverflow: false,\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",
"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 hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: 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",
"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 \"enableStickyHeader\": {\n \"title\": \"Always display header\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"enableStickyAction\": {\n \"title\": \"Always display actions column\",\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 \"useRowStyleFunction\": {\n \"title\": \"Use row style function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"rowStyleFunction\": {\n \"title\": \"Row style function: f(entity, ctx)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"entitiesTitle\",\n \"enableSearch\",\n \"enableSelectColumnDisplay\",\n \"enableStickyHeader\",\n \"enableStickyAction\",\n \"displayEntityName\",\n \"entityNameColumnTitle\",\n \"displayEntityLabel\",\n \"entityLabelColumnTitle\",\n \"displayEntityType\",\n \"displayPagination\",\n \"defaultPageSize\",\n \"defaultSortOrder\",\n \"useRowStyleFunction\",\n {\n \"key\": \"rowStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useRowStyleFunction === true\"\n }\n ]\n}",
"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, entity, ctx)\",\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 \"defaultColumnVisibility\": {\n \"title\": \"Default column visibility\",\n \"type\": \"string\",\n \"default\": \"visible\"\n },\n \"columnSelectionToDisplay\": {\n \"title\": \"Column selection in 'Columns to Display'\",\n \"type\": \"string\",\n \"default\": \"enabled\"\n }\n },\n \"required\": []\n },\n \"form\": [\n \"columnWidth\",\n \"useCellStyleFunction\",\n {\n \"key\": \"cellStyleFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellStyleFunction === true\"\n },\n \"useCellContentFunction\",\n {\n \"key\": \"cellContentFunction\",\n \"type\": \"javascript\",\n \"condition\": \"model.useCellContentFunction === true\"\n },\n {\n \"key\": \"defaultColumnVisibility\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"visible\",\n \"label\": \"Visible\"\n },\n {\n \"value\": \"hidden\",\n \"label\": \"Hidden\"\n } \n ]\n },\n {\n \"key\": \"columnSelectionToDisplay\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"enabled\",\n \"label\": \"Enabled\"\n },\n {\n \"value\": \"disabled\",\n \"label\": \"Disabled\"\n } \n ]\n }\n ]\n}",
"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;\"}]}]}"

View File

@ -40,7 +40,6 @@ import {
import { UtilsService } from '@core/services/utils.service';
import {
WidgetActionSource,
widgetActionSources,
WidgetActionType,
widgetActionTypeTranslationMap
} from '@shared/models/widget.models';
@ -150,13 +149,13 @@ export class WidgetActionDialogComponent extends DialogComponent<WidgetActionDia
}
displayShowWidgetActionForm(): boolean {
return this.widgetActionFormGroup.get('actionSourceId').value === widgetActionSources.headerButton.value;
return !!this.data.actionsData.actionSources[this.widgetActionFormGroup.get('actionSourceId').value]?.hasShowCondition;
}
private updateShowWidgetActionForm() {
const actionSourceId = this.widgetActionFormGroup.get('actionSourceId').value;
const useShowWidgetActionFunction = this.widgetActionFormGroup.get('useShowWidgetActionFunction').value;
if (actionSourceId === widgetActionSources.headerButton.value && useShowWidgetActionFunction) {
if (!!this.data.actionsData.actionSources[actionSourceId]?.hasShowCondition && useShowWidgetActionFunction) {
this.widgetActionFormGroup.get('showWidgetActionFunction').setValidators([Validators.required]);
} else {
this.widgetActionFormGroup.get('showWidgetActionFunction').clearValidators();

View File

@ -87,35 +87,40 @@
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" [stickyEnd]="enableStickyAction">
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: (actionCellDescriptors.length * 40) + 'px',
maxWidth: (actionCellDescriptors.length * 40) + 'px',
width: (actionCellDescriptors.length * 40) + 'px' }">
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: (countCellButtonAction * 40) + 'px',
maxWidth: (countCellButtonAction * 40) + 'px',
width: (countCellButtonAction * 40) + 'px' }">
</mat-header-cell>
<mat-cell *matCellDef="let alarm" [ngStyle.gt-md]="{ minWidth: (actionCellDescriptors.length * 40) + 'px',
maxWidth: (actionCellDescriptors.length * 40) + 'px',
width: (actionCellDescriptors.length * 40) + 'px' }">
<mat-cell *matCellDef="let alarm" [ngStyle.gt-md]="{ minWidth: (countCellButtonAction * 40) + 'px',
maxWidth: (countCellButtonAction * 40) + 'px',
width: (countCellButtonAction * 40) + 'px' }">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-button mat-icon-button [disabled]="(isLoading$ | async) || !actionEnabled(alarm, actionDescriptor)"
*ngFor="let actionDescriptor of actionCellDescriptors; trackBy: trackByActionCellDescriptionId"
matTooltip="{{ actionDescriptor.displayName }}"
matTooltipPosition="above"
(click)="onActionButtonClick($event, alarm, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
</button>
<ng-container *ngFor="let actionDescriptor of alarm.actionCellButtons; trackBy: trackByActionCellDescriptionId">
<span *ngIf="!actionDescriptor.icon" style="width: 40px;"></span>
<button mat-button mat-icon-button [disabled]="(isLoading$ | async) || !actionEnabled(alarm, actionDescriptor)"
*ngIf="actionDescriptor.icon"
matTooltip="{{ actionDescriptor.displayName }}"
matTooltipPosition="above"
(click)="onActionButtonClick($event, alarm, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
</button>
</ng-container>
</div>
<div fxHide fxShow.lt-lg *ngIf="actionCellDescriptors.length">
<div fxHide fxShow.lt-lg *ngIf="alarm.hasActions">
<button mat-button mat-icon-button
(click)="$event.stopPropagation(); ctx.detectChanges();"
[matMenuTriggerFor]="cellActionsMenu">
<mat-icon class="material-icons">more_vert</mat-icon>
</button>
<mat-menu #cellActionsMenu="matMenu" xPosition="before">
<button mat-menu-item *ngFor="let actionDescriptor of actionCellDescriptors; trackBy: trackByActionCellDescriptionId"
[disabled]="(isLoading$ | async) || !actionEnabled(alarm, actionDescriptor)"
(click)="onActionButtonClick($event, alarm, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
<ng-container *ngFor="let actionDescriptor of alarm.actionCellButtons; trackBy: trackByActionCellDescriptionId">
<button mat-menu-item *ngIf="actionDescriptor.icon"
[disabled]="(isLoading$ | async) || !actionEnabled(alarm, actionDescriptor)"
(click)="onActionButtonClick($event, alarm, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
</ng-container>
</mat-menu>
</div>
</mat-cell>

View File

@ -58,6 +58,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import {
CellContentInfo,
CellStyleInfo,
checkHasActions,
constructTableCssString,
DisplayColumn,
EntityColumn,
@ -72,7 +73,10 @@ import {
getColumnSelectionAvailability,
getColumnWidth,
getRowStyleInfo,
getTableCellButtonActions,
prepareTableCellButtonActions,
RowStyleInfo,
TableCellButtonActionDescriptor,
TableWidgetDataKeySettings,
TableWidgetSettings,
widthStyle
@ -130,7 +134,7 @@ interface AlarmsTableWidgetSettings extends TableWidgetSettings {
allowClear: boolean;
}
interface AlarmWidgetActionDescriptor extends WidgetActionDescriptor {
interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor {
details?: boolean;
acknowledge?: boolean;
clear?: boolean;
@ -160,8 +164,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
public textSearchMode = false;
public columns: Array<EntityColumn> = [];
public displayedColumns: string[] = [];
public actionCellDescriptors: AlarmWidgetActionDescriptor[] = [];
public alarmsDatasource: AlarmsDatasource;
public countCellButtonAction: number;
private cellContentCache: Array<any> = [];
private cellStyleCache: Array<any> = [];
@ -288,38 +292,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
this.allowAcknowledgment = isDefined(this.settings.allowAcknowledgment) ? this.settings.allowAcknowledgment : true;
this.allowClear = isDefined(this.settings.allowClear) ? this.settings.allowClear : true;
if (this.displayDetails) {
this.actionCellDescriptors.push(
{
displayName: this.translate.instant('alarm.details'),
icon: 'more_horiz',
details: true
} as AlarmWidgetActionDescriptor
);
}
if (this.allowAcknowledgment) {
this.actionCellDescriptors.push(
{
displayName: this.translate.instant('alarm.acknowledge'),
icon: 'done',
acknowledge: true
} as AlarmWidgetActionDescriptor
);
}
if (this.allowClear) {
this.actionCellDescriptors.push(
{
displayName: this.translate.instant('alarm.clear'),
icon: 'clear',
clear: true
} as AlarmWidgetActionDescriptor
);
}
this.actionCellDescriptors = this.actionCellDescriptors.concat(this.ctx.actionsApi.getActionDescriptors('actionCellButton'));
if (this.settings.alarmsTitle && this.settings.alarmsTitle.length) {
this.alarmsTitlePattern = this.utils.customTranslation(this.settings.alarmsTitle, this.settings.alarmsTitle);
} else {
@ -436,11 +408,44 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
}
this.sortOrderProperty = sortColumn ? sortColumn.def : null;
if (this.actionCellDescriptors.length) {
const actionCellDescriptors: AlarmWidgetActionDescriptor[] = [];
if (this.displayDetails) {
actionCellDescriptors.push(
{
displayName: this.translate.instant('alarm.details'),
icon: 'more_horiz',
details: true
} as AlarmWidgetActionDescriptor
);
}
if (this.allowAcknowledgment) {
actionCellDescriptors.push(
{
displayName: this.translate.instant('alarm.acknowledge'),
icon: 'done',
acknowledge: true
} as AlarmWidgetActionDescriptor
);
}
if (this.allowClear) {
actionCellDescriptors.push(
{
displayName: this.translate.instant('alarm.clear'),
icon: 'clear',
clear: true
} as AlarmWidgetActionDescriptor
);
}
this.countCellButtonAction = actionCellDescriptors.length + this.ctx.actionsApi.getActionDescriptors('actionCellButton').length;
if (this.countCellButtonAction) {
this.displayedColumns.push('actions');
}
this.alarmsDatasource = new AlarmsDatasource(this.subscription, latestDataKeys, this.ngZone);
this.alarmsDatasource = new AlarmsDatasource(this.subscription, latestDataKeys, this.ngZone, this.ctx, actionCellDescriptors);
if (this.enableSelection) {
this.alarmsDatasource.selectionModeChanged$.subscribe((selectionMode) => {
const hideTitlePanel = selectionMode || this.textSearchMode;
@ -495,7 +500,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
if (this.enableSelection) {
this.displayedColumns.unshift('select');
}
if (this.actionCellDescriptors.length) {
if (this.countCellButtonAction) {
this.displayedColumns.push('actions');
}
this.clearCache();
@ -986,9 +991,16 @@ class AlarmsDatasource implements DataSource<AlarmDataInfo> {
private appliedPageLink: AlarmDataPageLink;
private appliedSortOrderLabel: string;
private cellButtonActions: TableCellButtonActionDescriptor[];
private readonly usedShowCellActionFunction: boolean;
constructor(private subscription: IWidgetSubscription,
private dataKeys: Array<DataKey>,
private ngZone: NgZone) {
private ngZone: NgZone,
private widgetContext: WidgetContext,
actionCellDescriptors: AlarmWidgetActionDescriptor[]) {
this.cellButtonActions = actionCellDescriptors.concat(getTableCellButtonActions(widgetContext));
this.usedShowCellActionFunction = this.cellButtonActions.some(action => action.useShowActionCellButtonFunction);
}
connect(collectionViewer: CollectionViewer): Observable<AlarmDataInfo[] | ReadonlyArray<AlarmDataInfo>> {
@ -1069,6 +1081,15 @@ class AlarmsDatasource implements DataSource<AlarmDataInfo> {
}
alarm[dataKey.label] = value;
});
if (this.cellButtonActions.length) {
if (this.usedShowCellActionFunction) {
alarm.actionCellButtons = prepareTableCellButtonActions(this.widgetContext, this.cellButtonActions, alarm);
alarm.hasActions = checkHasActions(alarm.actionCellButtons);
} else {
alarm.actionCellButtons = this.cellButtonActions;
alarm.hasActions = true;
}
}
return alarm;
}

View File

@ -48,35 +48,40 @@
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" [stickyEnd]="enableStickyAction">
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: (actionCellDescriptors.length * 40) + 'px',
maxWidth: (actionCellDescriptors.length * 40) + 'px',
width: (actionCellDescriptors.length * 40) + 'px' }">
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: (countCellButtonAction * 40) + 'px',
maxWidth: (countCellButtonAction * 40) + 'px',
width: (countCellButtonAction * 40) + 'px' }">
</mat-header-cell>
<mat-cell *matCellDef="let entity" [ngStyle.gt-md]="{ minWidth: (actionCellDescriptors.length * 40) + 'px',
maxWidth: (actionCellDescriptors.length * 40) + 'px',
width: (actionCellDescriptors.length * 40) + 'px' }">
<mat-cell *matCellDef="let entity" [ngStyle.gt-md]="{ minWidth: (countCellButtonAction * 40) + 'px',
maxWidth: (countCellButtonAction * 40) + 'px',
width: (countCellButtonAction * 40) + 'px' }">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
*ngFor="let actionDescriptor of actionCellDescriptors; trackBy: trackByActionCellDescriptionId"
matTooltip="{{ actionDescriptor.displayName }}"
matTooltipPosition="above"
(click)="onActionButtonClick($event, entity, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
</button>
<ng-container *ngFor="let actionDescriptor of entity.actionCellButtons; trackBy: trackByActionCellDescriptionId">
<span *ngIf="!actionDescriptor.icon" style="width: 40px;"></span>
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
*ngIf="actionDescriptor.icon"
matTooltip="{{ actionDescriptor.displayName }}"
matTooltipPosition="above"
(click)="onActionButtonClick($event, entity, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
</button>
</ng-container>
</div>
<div fxHide fxShow.lt-lg *ngIf="actionCellDescriptors.length">
<div fxHide fxShow.lt-lg *ngIf="entity.hasActions">
<button mat-button mat-icon-button
(click)="$event.stopPropagation(); ctx.detectChanges();"
[matMenuTriggerFor]="cellActionsMenu">
<mat-icon class="material-icons">more_vert</mat-icon>
</button>
<mat-menu #cellActionsMenu="matMenu" xPosition="before">
<button mat-menu-item *ngFor="let actionDescriptor of actionCellDescriptors; trackBy: trackByActionCellDescriptionId"
[disabled]="isLoading$ | async"
(click)="onActionButtonClick($event, entity, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
<ng-container *ngFor="let actionDescriptor of entity.actionCellButtons; trackBy: trackByActionCellDescriptionId">
<button mat-menu-item *ngIf="actionDescriptor.icon"
[disabled]="isLoading$ | async"
(click)="onActionButtonClick($event, entity, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
</ng-container>
</mat-menu>
</div>
</mat-cell>

View File

@ -63,6 +63,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import {
CellContentInfo,
CellStyleInfo,
checkHasActions,
constructTableCssString,
DisplayColumn,
EntityColumn,
@ -78,7 +79,10 @@ import {
getColumnWidth,
getEntityValue,
getRowStyleInfo,
getTableCellButtonActions,
prepareTableCellButtonActions,
RowStyleInfo,
TableCellButtonActionDescriptor,
TableWidgetDataKeySettings,
TableWidgetSettings,
widthStyle
@ -136,8 +140,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
public textSearchMode = false;
public columns: Array<EntityColumn> = [];
public displayedColumns: string[] = [];
public actionCellDescriptors: WidgetActionDescriptor[];
public entityDatasource: EntityDatasource;
public countCellButtonAction: number;
private cellContentCache: Array<any> = [];
private cellStyleCache: Array<any> = [];
@ -245,7 +249,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
private initializeConfig() {
this.ctx.widgetActions = [this.searchAction, this.columnDisplayAction];
this.actionCellDescriptors = this.ctx.actionsApi.getActionDescriptors('actionCellButton');
this.countCellButtonAction = this.ctx.actionsApi.getActionDescriptors('actionCellButton').length;
if (this.settings.entitiesTitle && this.settings.entitiesTitle.length) {
this.entitiesTitlePattern = this.utils.customTranslation(this.settings.entitiesTitle, this.settings.entitiesTitle);
@ -426,10 +430,10 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
}
this.sortOrderProperty = sortColumn ? sortColumn.def : null;
if (this.actionCellDescriptors.length) {
if (this.countCellButtonAction) {
this.displayedColumns.push('actions');
}
this.entityDatasource = new EntityDatasource(this.translate, dataKeys, this.subscription, this.ngZone);
this.entityDatasource = new EntityDatasource(this.translate, dataKeys, this.subscription, this.ngZone, this.ctx);
}
private editColumnsToDisplay($event: Event) {
@ -470,7 +474,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
columns,
columnsUpdated: (newColumns) => {
this.displayedColumns = newColumns.filter(column => column.display).map(column => column.def);
if (this.actionCellDescriptors.length) {
if (this.countCellButtonAction) {
this.displayedColumns.push('actions');
}
this.clearCache();
@ -713,12 +717,18 @@ class EntityDatasource implements DataSource<EntityData> {
private appliedPageLink: EntityDataPageLink;
private appliedSortOrderLabel: string;
private cellButtonActions: TableCellButtonActionDescriptor[];
private readonly usedShowCellActionFunction: boolean;
constructor(
private translate: TranslateService,
private dataKeys: Array<DataKey>,
private subscription: IWidgetSubscription,
private ngZone: NgZone
private ngZone: NgZone,
private widgetContext: WidgetContext
) {
this.cellButtonActions = getTableCellButtonActions(widgetContext);
this.usedShowCellActionFunction = this.cellButtonActions.some(action => action.useShowActionCellButtonFunction);
}
connect(collectionViewer: CollectionViewer): Observable<EntityData[] | ReadonlyArray<EntityData>> {
@ -792,6 +802,15 @@ class EntityDatasource implements DataSource<EntityData> {
entity[dataKey.label] = '';
}
});
if (this.cellButtonActions.length) {
if (this.usedShowCellActionFunction) {
entity.actionCellButtons = prepareTableCellButtonActions(this.widgetContext, this.cellButtonActions, entity);
entity.hasActions = checkHasActions(entity.actionCellButtons);
} else {
entity.actionCellButtons = this.cellButtonActions;
entity.hasActions = true;
}
}
return entity;
}

View File

@ -318,7 +318,7 @@ export const parseWithTranslation = {
}
};
export function parseData(input: DatasourceData[]): FormattedData[] {
export function parseData(input: DatasourceData[], dataIndex?: number): FormattedData[] {
return _(input).groupBy(el => el?.datasource.entityName + el?.datasource.entityType)
.values().value().map((entityArray, i) => {
const obj: FormattedData = {
@ -330,12 +330,12 @@ export function parseData(input: DatasourceData[]): FormattedData[] {
deviceType: null
};
entityArray.filter(el => el.data.length).forEach(el => {
const indexDate = el.data.length - 1;
if (!obj.hasOwnProperty(el.dataKey.label) || el.data[indexDate][1] !== '') {
obj[el.dataKey.label] = el.data[indexDate][1];
obj[el.dataKey.label + '|ts'] = el.data[indexDate][0];
dataIndex = isDefined(dataIndex) ? dataIndex : el.data.length - 1;
if (!obj.hasOwnProperty(el.dataKey.label) || el.data[dataIndex][1] !== '') {
obj[el.dataKey.label] = el.data[dataIndex][1];
obj[el.dataKey.label + '|ts'] = el.data[dataIndex][0];
if (el.dataKey.label === 'type') {
obj.deviceType = el.data[indexDate][1];
obj.deviceType = el.data[dataIndex][1];
}
}
});

View File

@ -15,12 +15,14 @@
///
import { EntityId } from '@shared/models/id/entity-id';
import { DataKey, WidgetConfig } from '@shared/models/widget.models';
import { getDescendantProp, isDefined } from '@core/utils';
import { DataKey, WidgetActionDescriptor, WidgetConfig } from '@shared/models/widget.models';
import { getDescendantProp, isDefined, isNotEmptyStr } from '@core/utils';
import { AlarmDataInfo, alarmFields } from '@shared/models/alarm.models';
import * as tinycolor_ from 'tinycolor2';
import { Direction, EntityDataSortOrder, EntityKey } from '@shared/models/query/query.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { WidgetContext } from '@home/models/widget-component.models';
import { FormattedData } from '@home/components/widget/lib/maps/map-models';
const tinycolor = tinycolor_;
@ -48,11 +50,20 @@ export interface TableWidgetDataKeySettings {
columnSelectionToDisplay?: ColumnSelectionOptions;
}
export type ShowCellButtonActionFunction = (ctx: WidgetContext, data: EntityData | AlarmDataInfo | FormattedData) => boolean;
export interface TableCellButtonActionDescriptor extends WidgetActionDescriptor {
useShowActionCellButtonFunction: boolean;
showActionCellButtonFunction: ShowCellButtonActionFunction;
}
export interface EntityData {
id: EntityId;
entityName: string;
entityLabel?: string;
entityType?: string;
actionCellButtons?: TableCellButtonActionDescriptor[];
hasActions?: boolean;
[key: string]: any;
}
@ -296,6 +307,45 @@ export function getColumnSelectionAvailability(keySettings: TableWidgetDataKeySe
return !(isDefined(keySettings.columnSelectionToDisplay) && keySettings.columnSelectionToDisplay === 'disabled');
}
export function getTableCellButtonActions(widgetContext: WidgetContext): TableCellButtonActionDescriptor[] {
return widgetContext.actionsApi.getActionDescriptors('actionCellButton').map(descriptor => {
let useShowActionCellButtonFunction = descriptor.useShowWidgetActionFunction || false;
let showActionCellButtonFunction: ShowCellButtonActionFunction = null;
if (useShowActionCellButtonFunction && isNotEmptyStr(descriptor.showWidgetActionFunction)) {
try {
showActionCellButtonFunction =
new Function('widgetContext', 'data', descriptor.showWidgetActionFunction) as ShowCellButtonActionFunction;
} catch (e) {
useShowActionCellButtonFunction = false;
}
}
return {...descriptor, showActionCellButtonFunction, useShowActionCellButtonFunction};
});
}
export function checkHasActions(cellButtonActions: TableCellButtonActionDescriptor[]): boolean {
return cellButtonActions.some(action => action.icon);
}
export function prepareTableCellButtonActions(widgetContext: WidgetContext, cellButtonActions: TableCellButtonActionDescriptor[],
data: EntityData | AlarmDataInfo | FormattedData): TableCellButtonActionDescriptor[] {
return cellButtonActions.map(action =>
filterTableCellButtonAction(widgetContext, action, data) ? action : { id: action.id } as TableCellButtonActionDescriptor);
}
function filterTableCellButtonAction(widgetContext: WidgetContext,
action: TableCellButtonActionDescriptor, data: EntityData | AlarmDataInfo | FormattedData): boolean {
if (action.useShowActionCellButtonFunction) {
try {
return action.showActionCellButtonFunction(widgetContext, data);
} catch (e) {
console.warn('Failed to execute showActionCellButtonFunction', e);
return false;
}
} else {
return true;
}
}
export function constructTableCssString(widgetConfig: WidgetConfig): string {
const origColor = widgetConfig.color || 'rgba(0, 0, 0, 0.87)';

View File

@ -59,35 +59,40 @@
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" [stickyEnd]="enableStickyAction">
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: (actionCellDescriptors.length * 40) + 'px',
maxWidth: (actionCellDescriptors.length * 40) + 'px',
width: (actionCellDescriptors.length * 40) + 'px' }">
<mat-header-cell *matHeaderCellDef [ngStyle.gt-md]="{ minWidth: (countCellButtonAction * 40) + 'px',
maxWidth: (countCellButtonAction * 40) + 'px',
width: (countCellButtonAction * 40) + 'px' }">
</mat-header-cell>
<mat-cell *matCellDef="let row" [ngStyle.gt-md]="{ minWidth: (actionCellDescriptors.length * 40) + 'px',
maxWidth: (actionCellDescriptors.length * 40) + 'px',
width: (actionCellDescriptors.length * 40) + 'px' }">
<mat-cell *matCellDef="let row" [ngStyle.gt-md]="{ minWidth: (countCellButtonAction * 40) + 'px',
maxWidth: (countCellButtonAction * 40) + 'px',
width: (countCellButtonAction * 40) + 'px' }">
<div fxHide fxShow.gt-md fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-button mat-icon-button [disabled]="isLoading$ | async"
*ngFor="let actionDescriptor of actionCellDescriptors; trackBy: trackByActionCellDescriptionId"
matTooltip="{{ actionDescriptor.displayName }}"
matTooltipPosition="above"
(click)="onActionButtonClick($event, row, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
</button>
<ng-container *ngFor="let actionDescriptor of row.actionCellButtons; trackBy: trackByActionCellDescriptionId">
<span *ngIf="!actionDescriptor.icon" style="width: 40px;"></span>
<button *ngIf="actionDescriptor.icon"
mat-button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ actionDescriptor.displayName }}"
matTooltipPosition="above"
(click)="onActionButtonClick($event, row, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
</button>
</ng-container>
</div>
<div fxHide fxShow.lt-lg *ngIf="actionCellDescriptors.length">
<div fxHide fxShow.lt-lg *ngIf="row.hasActions">
<button mat-button mat-icon-button
(click)="$event.stopPropagation(); ctx.detectChanges();"
[matMenuTriggerFor]="cellActionsMenu">
<mat-icon class="material-icons">more_vert</mat-icon>
</button>
<mat-menu #cellActionsMenu="matMenu" xPosition="before">
<button mat-menu-item *ngFor="let actionDescriptor of actionCellDescriptors; trackBy: trackByActionCellDescriptionId"
[disabled]="isLoading$ | async"
(click)="onActionButtonClick($event, row, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
<ng-container *ngFor="let actionDescriptor of row.actionCellButtons; trackBy: trackByActionCellDescriptionId">
<button mat-menu-item *ngIf="actionDescriptor.icon"
[disabled]="isLoading$ | async"
(click)="onActionButtonClick($event, row, actionDescriptor)">
<mat-icon>{{actionDescriptor.icon}}</mat-icon>
<span>{{ actionDescriptor.displayName }}</span>
</button>
</ng-container>
</mat-menu>
</div>
</mat-cell>

View File

@ -53,17 +53,22 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import {
CellContentInfo,
CellStyleInfo,
checkHasActions,
constructTableCssString,
getCellContentInfo,
getCellStyleInfo,
getRowStyleInfo,
getTableCellButtonActions,
prepareTableCellButtonActions,
RowStyleInfo,
TableCellButtonActionDescriptor,
TableWidgetDataKeySettings,
TableWidgetSettings
} from '@home/components/widget/lib/table-widget.models';
import { Overlay } from '@angular/cdk/overlay';
import { SubscriptionEntityInfo } from '@core/api/widget-api.models';
import { DatePipe } from '@angular/common';
import { parseData } from '@home/components/widget/lib/maps/common-maps-utils';
export interface TimeseriesTableWidgetSettings extends TableWidgetSettings {
showTimestamp: boolean;
@ -72,6 +77,8 @@ export interface TimeseriesTableWidgetSettings extends TableWidgetSettings {
}
interface TimeseriesRow {
actionCellButtons?: TableCellButtonActionDescriptor[];
hasActions?: boolean;
[col: number]: any;
formattedTs: string;
}
@ -116,9 +123,9 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
public pageSizeOptions;
public textSearchMode = false;
public textSearch: string = null;
public actionCellDescriptors: WidgetActionDescriptor[];
public sources: TimeseriesTableSource[];
public sourceIndex: number;
public countCellButtonAction: number;
private cellContentCache: Array<any> = [];
private cellStyleCache: Array<any> = [];
@ -204,7 +211,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
private initialize() {
this.ctx.widgetActions = [this.searchAction ];
this.actionCellDescriptors = this.ctx.actionsApi.getActionDescriptors('actionCellButton');
this.countCellButtonAction = this.ctx.actionsApi.getActionDescriptors('actionCellButton').length;
this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true;
this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true;
@ -288,10 +295,10 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
cellContentInfo.decimals = dataKey.decimals;
source.contentsInfo.push(cellContentInfo);
}
if (this.actionCellDescriptors.length) {
if (this.countCellButtonAction) {
source.displayedColumns.push('actions');
}
const tsDatasource = new TimeseriesDatasource(source, this.hideEmptyLines, this.dateFormatFilter, this.datePipe);
const tsDatasource = new TimeseriesDatasource(source, this.hideEmptyLines, this.dateFormatFilter, this.datePipe, this.ctx);
tsDatasource.dataUpdated(this.data);
this.sources.push(source);
}
@ -570,12 +577,18 @@ class TimeseriesDatasource implements DataSource<TimeseriesRow> {
private allRowsSubject = new BehaviorSubject<TimeseriesRow[]>([]);
private allRows$: Observable<Array<TimeseriesRow>> = this.allRowsSubject.asObservable();
private cellButtonActions: TableCellButtonActionDescriptor[];
private readonly usedShowCellActionFunction: boolean;
constructor(
private source: TimeseriesTableSource,
private hideEmptyLines: boolean,
private dateFormatFilter: string,
private datePipe: DatePipe
private datePipe: DatePipe,
private widgetContext: WidgetContext
) {
this.cellButtonActions = getTableCellButtonActions(widgetContext);
this.usedShowCellActionFunction = this.cellButtonActions.some(action => action.useShowActionCellButtonFunction);
this.source.timeseriesDatasource = this;
}
@ -617,13 +630,23 @@ class TimeseriesDatasource implements DataSource<TimeseriesRow> {
const rowsMap: {[timestamp: number]: TimeseriesRow} = {};
for (let d = 0; d < data.length; d++) {
const columnData = data[d].data;
columnData.forEach((cellData) => {
columnData.forEach((cellData, index) => {
const timestamp = cellData[0];
let row = rowsMap[timestamp];
if (!row) {
row = {
formattedTs: this.datePipe.transform(timestamp, this.dateFormatFilter)
};
if (this.cellButtonActions.length) {
if (this.usedShowCellActionFunction) {
const parsedData = parseData(data, index);
row.actionCellButtons = prepareTableCellButtonActions(this.widgetContext, this.cellButtonActions, parsedData[0]);
row.hasActions = checkHasActions(row.actionCellButtons);
} else {
row.hasActions = true;
row.actionCellButtons = this.cellButtonActions;
}
}
row[0] = timestamp;
for (let c = 0; c < data.length; c++) {
row[c + 1] = undefined;

View File

@ -22,6 +22,7 @@ import { TimePageLink } from '@shared/models/page/page-link';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { EntityType } from '@shared/models/entity-type.models';
import { CustomerId } from '@shared/models/id/customer-id';
import { TableCellButtonActionDescriptor } from '@home/components/widget/lib/table-widget.models';
export enum AlarmSeverity {
CRITICAL = 'CRITICAL',
@ -105,6 +106,8 @@ export interface AlarmInfo extends Alarm {
}
export interface AlarmDataInfo extends AlarmInfo {
actionCellButtons?: TableCellButtonActionDescriptor[];
hasActions?: boolean;
[key: string]: any;
}

View File

@ -121,6 +121,7 @@ export interface WidgetActionSource {
name: string;
value: string;
multiple: boolean;
hasShowCondition?: boolean;
}
export const widgetActionSources: {[acionSourceId: string]: WidgetActionSource} = {
@ -129,6 +130,7 @@ export const widgetActionSources: {[acionSourceId: string]: WidgetActionSource}
name: 'widget-action.header-button',
value: 'headerButton',
multiple: true,
hasShowCondition: true
}
};