UI: Added conditionally show widget table cell button action
This commit is contained in:
		
							parent
							
								
									23121c5b5a
								
							
						
					
					
						commit
						814a685d76
					
				@ -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}"
 | 
			
		||||
 | 
			
		||||
@ -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;\"}]}]}"
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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];
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@ -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)';
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user