diff --git a/application/src/main/data/json/system/widget_bundles/edge_widgets.json b/application/src/main/data/json/system/widget_bundles/edge_widgets.json index 9cabfe53fb..74e6138827 100644 --- a/application/src/main/data/json/system/widget_bundles/edge_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/edge_widgets.json @@ -15,11 +15,11 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.edgesOverviewWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'nodeSelected': {\n name: 'widget-action.node-selected',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EdgesOverviewSettings\",\n \"properties\": {\n \"nodeRelationQueryFunction\": {\n \"title\": \"Node relations query function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeHasChildrenFunction\": {\n \"title\": \"Node has children function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeOpenedFunction\": {\n \"title\": \"Default node opened function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeDisabledFunction\": {\n \"title\": \"Node disabled function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeIconFunction\": {\n \"title\": \"Node icon function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodeTextFunction\": {\n \"title\": \"Node text function: f(nodeCtx)\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"nodesSortFunction\": {\n \"title\": \"Nodes sort function: f(nodeCtx1, nodeCtx2)\",\n \"type\": \"string\",\n \"default\": \"\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"nodeRelationQueryFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeHasChildrenFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeOpenedFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeDisabledFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeIconFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodeTextFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"nodesSortFunction\",\n \"type\": \"javascript\"\n }\n ]\n}", - "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {},\n \"required\": []\n },\n \"form\": []\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\":{\"nodeRelationQueryFunction\":\"/**\\n\\n// Function should return relations query object for current node used to fetch entity children.\\n// Function can return 'default' string value. In this case default relations query will be used.\\n\\n// The following example code will construct simple relations query that will fetch relations of type 'Contains'\\n// from the current entity.\\n\\nvar entity = nodeCtx.entity;\\nvar query = {\\n parameters: {\\n rootId: entity.id.id,\\n rootType: entity.id.entityType,\\n direction: \\\"FROM\\\",\\n maxLevel: 1\\n },\\n filters: [{\\n relationType: \\\"Contains\\\",\\n entityTypes: []\\n }]\\n};\\nreturn query;\\n\\n**/\\n\",\"nodeHasChildrenFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node has children (whether it can be expanded).\\n\\n// The following example code will restrict entities hierarchy expansion up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n// The next example code will restrict entities expansion according to the value of example 'nodeHasChildren' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeHasChildren') && data['nodeHasChildren'] !== null) {\\n return data['nodeHasChildren'] === 'true';\\n} else {\\n return true;\\n}\\n \\n**/\\n \",\"nodeTextFunction\":\"/**\\n\\n// Function should return text (can be HTML code) for the current node.\\n\\n// The following example code will generate node text consisting of entity name and temperature if temperature value is present in entity attributes/timeseries.\\n\\nvar data = nodeCtx.data;\\nvar entity = nodeCtx.entity;\\nvar text = entity.name;\\nif (data.hasOwnProperty('temperature') && data['temperature'] !== null) {\\n text += \\\" \\\"+ data['temperature'] +\\\" °C\\\";\\n}\\nreturn text;\\n\\n**/\",\"nodeIconFunction\":\"/** \\n\\n// Function should return node icon info object.\\n// Resulting object should contain either 'materialIcon' or 'iconUrl' property. \\n// Where:\\n - 'materialIcon' - name of the material icon to be used from the Material Icons Library (https://material.io/tools/icons);\\n - 'iconUrl' - url of the external image to be used as node icon.\\n// Function can return 'default' string value. In this case default icons according to entity type will be used.\\n\\n// The following example code shows how to use external image for devices which name starts with 'Test' and use \\n// default icons for the rest of entities.\\n\\nvar entity = nodeCtx.entity;\\nif (entity.id.entityType === 'DEVICE' && entity.name.startsWith('Test')) {\\n return {iconUrl: 'https://avatars1.githubusercontent.com/u/14793288?v=4&s=117'};\\n} else {\\n return 'default';\\n}\\n \\n**/\",\"nodeDisabledFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be disabled (not selectable).\\n\\n// The following example code will disable current node according to the value of example 'nodeDisabled' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeDisabled') && data['nodeDisabled'] !== null) {\\n return data['nodeDisabled'] === 'true';\\n} else {\\n return false;\\n}\\n \\n**/\\n\",\"nodesSortFunction\":\"/**\\n\\n// This function is used to sort nodes of the same level. Function should compare two nodes and return \\n// integer value: \\n// - less than 0 - sort nodeCtx1 to an index lower than nodeCtx2\\n// - 0 - leave nodeCtx1 and nodeCtx2 unchanged with respect to each other\\n// - greater than 0 - sort nodeCtx2 to an index lower than nodeCtx1\\n\\n// The following example code will sort entities first by entity type in alphabetical order then\\n// by entity name in alphabetical order.\\n\\nvar result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);\\nif (result === 0) {\\n result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name);\\n}\\nreturn result;\\n \\n**/\",\"nodeOpenedFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be opened (expanded) when it first loaded.\\n\\n// The following example code will open by default nodes up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n**/\\n \"},\"title\":\"Edge Quick Overview Widget\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"widgetStyle\":{},\"actions\":{}}" + "controllerScript": "self.onInit = function() {\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}\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\":{},\"title\":\"Edges Quick Overview\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#4caf50\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.8926244886945558,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#f44336\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6401141393938932,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"widgetStyle\":{},\"actions\":{}}" } } ] -} \ No newline at end of file +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.html index 859e79a95c..75baaf6340 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.html @@ -17,37 +17,13 @@ -->
- -
- - -   - - - -
-
{{ customerTitle }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts index bceef70764..05aa1b7ac4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.ts @@ -14,63 +14,46 @@ /// limitations under the License. /// -import { ChangeDetectorRef, AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + Input, + OnInit, + ViewChild, + ViewContainerRef +} from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { WidgetAction, WidgetContext } from '@home/models/widget-component.models'; -import { DatasourceData, DatasourceType, WidgetConfig, widgetType } from '@shared/models/widget.models'; -import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; +import { WidgetConfig } from '@shared/models/widget.models'; +import { IWidgetSubscription } from '@core/api/widget-api.models'; import { UtilsService } from '@core/services/utils.service'; import cssjs from '@core/css/css'; -import { fromEvent, Observable } from 'rxjs'; -import { debounceTime, distinctUntilChanged, map, mergeMap, tap } from 'rxjs/operators'; +import { fromEvent } from 'rxjs'; +import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; import { constructTableCssString } from '@home/components/widget/lib/table-widget.models'; import { Overlay } from '@angular/cdk/overlay'; import { LoadNodesCallback, - NavTreeEditCallbacks, - NodesCallback, - NodeSearchCallback, - NodeSelectedCallback, - NodesInsertedCallback + NavTreeEditCallbacks } from '@shared/components/nav-tree.component'; import { EntityType } from '@shared/models/entity-type.models'; -import { deepClone, hashCode } from '@core/utils'; +import { hashCode } from '@core/utils'; import { - defaultNodeIconFunction, - defaultNodeOpenedFunction, - defaultNodeRelationQueryFunction, - defaultNodesSortFunction, - EdgeGroupsNodeData, + EdgeGroupNodeData, edgeGroupsNodeText, - edgeGroupsTypes, - EdgeNodeData, + edgeGroupsTypes, EntityNodeData, edgeNodeText, - EdgeOverviewNode, EdgesOverviewWidgetSettings, - HierarchyNavTreeNode, - HierarchyNodeContext, - HierarchyNodeDatasource, - iconUrlHtml, - loadNodeCtxFunction, - materialIconHtml, - NodeDisabledFunction, - NodeHasChildrenFunction, - NodeIconFunction, - NodeOpenedFunction, - NodeRelationQueryFunction, - NodesSortFunction, - NodeTextFunction + EdgeOverviewNode, EntityNodeDatasource } from '@home/components/widget/lib/edges-overview-widget.models'; -import { EntityRelationsQuery } from '@shared/models/relation.models'; -import { AliasFilterType, RelationsQueryFilter } from '@shared/models/alias.models'; -import { EntityFilter } from '@shared/models/query/query.models'; import { EdgeService } from "@core/http/edge.service"; import { EntityService } from "@core/http/entity.service"; import { TranslateService } from "@ngx-translate/core"; -import { Direction, SortOrder } from "@shared/models/page/sort-order"; import { PageLink } from "@shared/models/page/page-link"; -import { Edge, EdgeInfo } from "@shared/models/edge.models"; +import { Edge } from "@shared/models/edge.models"; import { BaseData } from "@shared/models/base-data"; import { EntityId } from "@shared/models/id/entity-id"; @@ -79,7 +62,7 @@ import { EntityId } from "@shared/models/id/entity-id"; templateUrl: './edges-overview-widget.component.html', styleUrls: ['./edges-overview-widget.component.scss'] }) -export class EdgesOverviewWidgetComponent extends PageComponent implements OnInit, AfterViewInit { +export class EdgesOverviewWidgetComponent extends PageComponent implements OnInit { @Input() ctx: WidgetContext; @@ -87,44 +70,17 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni @ViewChild('searchInput') searchInputField: ElementRef; public toastTargetId = 'edges-overview-' + this.utils.guid(); - - public textSearchMode = false; - public textSearch = null; public customerTitle: string = null; - public nodeEditCallbacks: NavTreeEditCallbacks = {}; - - private settings: EdgesOverviewWidgetSettings; private widgetConfig: WidgetConfig; private subscription: IWidgetSubscription; - private datasources: Array; - private data: Array>; + private datasources: Array; - private nodesMap: {[nodeId: string]: HierarchyNavTreeNode} = {}; - private pendingUpdateNodeTasks: {[nodeId: string]: () => void} = {}; private nodeIdCounter = 0; - private nodeRelationQueryFunction: NodeRelationQueryFunction; - private nodeIconFunction: NodeIconFunction; - private nodeTextFunction: NodeTextFunction; - private nodeDisabledFunction: NodeDisabledFunction; - private nodeOpenedFunction: NodeOpenedFunction; - private nodeHasChildrenFunction: NodeHasChildrenFunction; - private nodesSortFunction: NodesSortFunction; - private edgeNodesMap: {[parentNodeId: string]: {[edgeId: string]: string}} = {}; private edgeGroupsNodesMap: {[edgeNodeId: string]: {[groupType: string]: string}} = {}; - - private searchAction: WidgetAction = { - name: 'action.search', - show: false, - icon: 'search', - onAction: () => { - this.enterFilterMode(); - } - }; - constructor(protected store: Store, private elementRef: ElementRef, private edgeService: EdgeService, @@ -138,72 +94,19 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni } ngOnInit(): void { - this.ctx.$scope.edgesOverviewWidget = this; - this.settings = this.ctx.settings; this.widgetConfig = this.ctx.widgetConfig; this.subscription = this.ctx.defaultSubscription; - this.datasources = this.subscription.datasources as Array; - this.data = this.subscription.dataPages[0].data; - this.ctx.widgetTitle = this.datasources[0].entity.name; - this.getCustomerTitle(this.datasources[0].entity.id.id); + this.datasources = this.subscription.datasources as Array; + if (this.datasources.length > 0 && this.datasources[0].entity.id.entityType === EntityType.EDGE) { + let selectedEdge = this.datasources[0].entity; + this.getCustomerTitle(selectedEdge.id.id); + this.ctx.widgetTitle = selectedEdge.name; + } this.initializeConfig(); this.ctx.updateWidgetParams(); } - ngAfterViewInit(): void { - fromEvent(this.searchInputField.nativeElement, 'keyup') - .pipe( - debounceTime(150), - distinctUntilChanged(), - tap(() => { - this.updateSearchNodes(); - }) - ) - .subscribe(); - } - - public onDataUpdated() { - this.updateNodeData(this.subscription.data); - } - private initializeConfig() { - this.ctx.widgetActions = [this.searchAction]; - - const testNodeCtx: HierarchyNodeContext = { - entity: { - id: { - entityType: EntityType.DEVICE, - id: '123' - }, - name: 'TEST DEV1' - }, - data: {}, - level: 2 - }; - const parentNodeCtx = deepClone(testNodeCtx); - parentNodeCtx.level = 1; - testNodeCtx.parentNodeCtx = parentNodeCtx; - - this.nodeRelationQueryFunction = loadNodeCtxFunction(this.settings.nodeRelationQueryFunction, 'nodeCtx', testNodeCtx); - this.nodeIconFunction = loadNodeCtxFunction(this.settings.nodeIconFunction, 'nodeCtx', testNodeCtx); - this.nodeTextFunction = loadNodeCtxFunction(this.settings.nodeTextFunction, 'nodeCtx', testNodeCtx); - this.nodeDisabledFunction = loadNodeCtxFunction(this.settings.nodeDisabledFunction, 'nodeCtx', testNodeCtx); - this.nodeOpenedFunction = loadNodeCtxFunction(this.settings.nodeOpenedFunction, 'nodeCtx', testNodeCtx); - this.nodeHasChildrenFunction = loadNodeCtxFunction(this.settings.nodeHasChildrenFunction, 'nodeCtx', testNodeCtx); - - const testNodeCtx2 = deepClone(testNodeCtx); - testNodeCtx2.entity.name = 'TEST DEV2'; - - this.nodesSortFunction = loadNodeCtxFunction(this.settings.nodesSortFunction, 'nodeCtx1,nodeCtx2', testNodeCtx, testNodeCtx2); - - this.nodeRelationQueryFunction = this.nodeRelationQueryFunction || defaultNodeRelationQueryFunction; - this.nodeIconFunction = this.nodeIconFunction || defaultNodeIconFunction; - this.nodeTextFunction = this.nodeTextFunction || ((nodeCtx) => nodeCtx.entity.name); - this.nodeDisabledFunction = this.nodeDisabledFunction || (() => false); - this.nodeOpenedFunction = this.nodeOpenedFunction || defaultNodeOpenedFunction; - this.nodeHasChildrenFunction = this.nodeHasChildrenFunction || (() => true); - this.nodesSortFunction = this.nodesSortFunction || defaultNodesSortFunction; - const cssString = constructTableCssString(this.widgetConfig); const cssParser = new cssjs(); cssParser.testMode = false; @@ -213,72 +116,14 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni $(this.elementRef.nativeElement).addClass(namespace); } - private enterFilterMode() { - this.textSearchMode = true; - this.textSearch = ''; - this.ctx.hideTitlePanel = true; - this.ctx.detectChanges(true); - setTimeout(() => { - this.searchInputField.nativeElement.focus(); - this.searchInputField.nativeElement.setSelectionRange(0, 0); - }, 10); - } - - exitFilterMode() { - this.textSearchMode = false; - this.textSearch = null; - this.updateSearchNodes(); - this.ctx.hideTitlePanel = false; - this.ctx.detectChanges(true); - } - - private updateSearchNodes() { - if (this.textSearch != null) { - this.nodeEditCallbacks.search(this.textSearch); - } else { - this.nodeEditCallbacks.clearSearch(); - } - } - - private updateNodeData(subscriptionData: Array) { - const affectedNodes: string[] = []; - if (subscriptionData) { - subscriptionData.forEach((datasourceData) => { - const datasource = datasourceData.datasource as HierarchyNodeDatasource; - if (datasource.nodeId) { - const node = this.nodesMap[datasource.nodeId]; - const key = datasourceData.dataKey.label; - let value; - if (datasourceData.data && datasourceData.data.length) { - value = datasourceData.data[0][1]; - } - if (node.data.nodeCtx.data[key] !== value) { - if (affectedNodes.indexOf(datasource.nodeId) === -1) { - affectedNodes.push(datasource.nodeId); - } - node.data.nodeCtx.data[key] = value; - } - } - }); - } - affectedNodes.forEach((nodeId) => { - const node: HierarchyNavTreeNode = this.nodeEditCallbacks.getNode(nodeId); - if (node) { - this.updateNodeStyle(this.nodesMap[nodeId]); - } else { - this.pendingUpdateNodeTasks[nodeId] = () => { - this.updateNodeStyle(this.nodesMap[nodeId]); - }; - } - }); - } - public loadNodes: LoadNodesCallback = (node, cb) => { - if (node.id === '#') { - const edge: BaseData = this.datasources[0].entity; - cb(this.loadNodesForEdge(edge.id.id, edge)); - } - else if (node.data.type === 'edgeGroups') { + var selectedEdge: BaseData = null; + if (this.datasources.length > 0 && this.datasources[0].entity && this.datasources[0].entity.id.entityType === EntityType.EDGE) { + selectedEdge = this.datasources[0].entity; + } + if (node.id === '#' && selectedEdge) { + cb(this.loadNodesForEdge(selectedEdge.id.id, selectedEdge)); + } else if (node.data && node.data.type === 'edgeGroup') { const pageLink = new PageLink(100); this.entityService.getAssignedToEdgeEntitiesByType(node, pageLink).subscribe( (entities) => { @@ -289,6 +134,8 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni } } ) + } else { + cb([]); } } @@ -303,11 +150,11 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni text: edgeGroupsNodeText(this.translateService, entityType), children: true, data: { - type: 'edgeGroups', + type: 'edgeGroup', entityType, edge, internalId: edge.id.id + '_' + entityType - } as EdgeGroupsNodeData + } as EdgeGroupNodeData }; nodes.push(node); nodesMap[entityType] = node.id; @@ -330,10 +177,10 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni disabled: false }, data: { - type: 'edge', + type: 'entity', entity: edge, internalId: edge.id.id - } as EdgeNodeData + } as EntityNodeData }; nodesMap[edge.id.id] = node.id; return node; @@ -351,94 +198,6 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni return nodes; } - public onNodeSelected: NodeSelectedCallback = (node, event) => { - let nodeId; - if (!node) { - nodeId = -1; - } else { - nodeId = node.id; - } - if (nodeId !== -1) { - const selectedNode = this.nodesMap[nodeId]; - if (selectedNode) { - const descriptors = this.ctx.actionsApi.getActionDescriptors('nodeSelected'); - if (descriptors.length) { - const entity = selectedNode.data.nodeCtx.entity; - this.ctx.actionsApi.handleWidgetAction(event, descriptors[0], entity.id, entity.name, { nodeCtx: selectedNode.data.nodeCtx }); - } - } - } - } - - public onNodesInserted: NodesInsertedCallback = (nodes) => { - if (nodes) { - nodes.forEach((nodeId) => { - const task = this.pendingUpdateNodeTasks[nodeId]; - if (task) { - task(); - delete this.pendingUpdateNodeTasks[nodeId]; - } - }); - } - } - - public searchCallback: NodeSearchCallback = (searchText, node) => { - const theNode = this.nodesMap[node.id]; - if (theNode && theNode.data.searchText) { - return theNode.data.searchText.includes(searchText.toLowerCase()); - } - return false; - } - - private updateNodeStyle(node: HierarchyNavTreeNode) { - const newText = this.prepareNodeText(node); - if (node.text !== newText) { - node.text = newText; - this.nodeEditCallbacks.updateNode(node.id, node.text); - } - const newDisabled = this.nodeDisabledFunction(node.data.nodeCtx); - if (node.state.disabled !== newDisabled) { - node.state.disabled = newDisabled; - if (node.state.disabled) { - this.nodeEditCallbacks.disableNode(node.id); - } else { - this.nodeEditCallbacks.enableNode(node.id); - } - } - const newHasChildren = this.nodeHasChildrenFunction(node.data.nodeCtx); - if (node.children !== newHasChildren) { - node.children = newHasChildren; - this.nodeEditCallbacks.setNodeHasChildren(node.id, node.children); - } - } - - private prepareNodeText(node: HierarchyNavTreeNode): string { - const nodeIcon = this.prepareNodeIcon(node.data.nodeCtx); - const nodeText = this.nodeTextFunction(node.data.nodeCtx); - node.data.searchText = nodeText ? nodeText.replace(/<[^>]+>/g, '').toLowerCase() : ''; - return nodeIcon + nodeText; - } - - private prepareNodeIcon(nodeCtx: HierarchyNodeContext): string { - let iconInfo = this.nodeIconFunction(nodeCtx); - if (iconInfo) { - if (iconInfo === 'default') { - iconInfo = defaultNodeIconFunction(nodeCtx); - } - if (iconInfo && iconInfo !== 'default' && (iconInfo.iconUrl || iconInfo.materialIcon)) { - if (iconInfo.materialIcon) { - return materialIconHtml(iconInfo.materialIcon); - } else { - return iconUrlHtml(iconInfo.iconUrl); - } - } else { - return ''; - } - } else { - return ''; - } - } - private getCustomerTitle(edgeId) { this.edgeService.getEdgeInfo(edgeId).subscribe( (edge) => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.models.ts index a838223098..6c26754c52 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.models.ts @@ -14,83 +14,16 @@ /// limitations under the License. /// -import { BaseData } from '@shared/models/base-data'; -import { EntityId } from '@shared/models/id/entity-id'; -import { NavTreeNode, NodesCallback } from '@shared/components/nav-tree.component'; +import { NavTreeNode } from '@shared/components/nav-tree.component'; import { Datasource } from '@shared/models/widget.models'; -import { isDefined, isUndefined } from '@core/utils'; -import { EntityRelationsQuery, EntitySearchDirection, RelationTypeGroup } from '@shared/models/relation.models'; import { EntityType } from '@shared/models/entity-type.models'; import { Edge } from "@shared/models/edge.models"; import { TranslateService } from "@ngx-translate/core"; -export interface EdgesOverviewWidgetSettings { - nodeRelationQueryFunction: string; - nodeHasChildrenFunction: string; - nodeOpenedFunction: string; - nodeDisabledFunction: string; - nodeIconFunction: string; - nodeTextFunction: string; - nodesSortFunction: string; -} - -export interface HierarchyNodeContext { - parentNodeCtx?: HierarchyNodeContext; - entity: BaseData; - childrenNodesLoaded?: boolean; - level?: number; - data: {[key: string]: any}; -} - -export interface HierarchyNavTreeNode extends NavTreeNode { - data?: { - datasource: HierarchyNodeDatasource; - nodeCtx: HierarchyNodeContext; - searchText?: string; - }; -} - -export interface HierarchyNodeDatasource extends Datasource { +export interface EntityNodeDatasource extends Datasource { nodeId: string; } -export interface HierarchyNodeIconInfo { - iconUrl?: string; - materialIcon?: string; -} - -export type NodeRelationQueryFunction = (nodeCtx: HierarchyNodeContext) => EntityRelationsQuery | 'default'; -export type NodeTextFunction = (nodeCtx: HierarchyNodeContext) => string; -export type NodeDisabledFunction = (nodeCtx: HierarchyNodeContext) => boolean; -export type NodeIconFunction = (nodeCtx: HierarchyNodeContext) => HierarchyNodeIconInfo | 'default'; -export type NodeOpenedFunction = (nodeCtx: HierarchyNodeContext) => boolean; -export type NodeHasChildrenFunction = (nodeCtx: HierarchyNodeContext) => boolean; -export type NodesSortFunction = (nodeCtx1: HierarchyNodeContext, nodeCtx2: HierarchyNodeContext) => number; - -export function loadNodeCtxFunction any>(functionBody: string, argNames: string, ...args: any[]): F { - let nodeCtxFunction: F = null; - if (isDefined(functionBody) && functionBody.length) { - try { - nodeCtxFunction = new Function(argNames, functionBody) as F; - const res = nodeCtxFunction.apply(null, args); - if (isUndefined(res)) { - nodeCtxFunction = null; - } - } catch (e) { - nodeCtxFunction = null; - } - } - return nodeCtxFunction; -} - -export function materialIconHtml(materialIcon: string): string { - return '' + materialIcon + ''; -} - -export function iconUrlHtml(iconUrl: string): string { - return '
 
'; -} - export function edgeGroupsNodeText(translate: TranslateService, entityType: EntityType): string { const nodeIcon = materialIconByEntityType(entityType); const nodeText = textForEdgeGroupsType(translate, entityType); @@ -112,12 +45,6 @@ export function materialIconByEntityType(entityType: EntityType): string { case EntityType.ASSET: materialIcon = 'domain'; break; - case EntityType.CUSTOMER: - materialIcon = 'supervisor_account'; - break; - case EntityType.USER: - materialIcon = 'account_circle'; - break; case EntityType.DASHBOARD: materialIcon = 'dashboards'; break; @@ -127,9 +54,6 @@ export function materialIconByEntityType(entityType: EntityType): string { case EntityType.RULE_CHAIN: materialIcon = 'settings_ethernet'; break; - case EntityType.EDGE: - materialIcon = 'router'; - break; } return '' + materialIcon + ''; } @@ -156,26 +80,6 @@ export function textForEdgeGroupsType(translate: TranslateService, entityType: E return translate.instant(textForEdgeGroupsType); } -export const defaultNodeRelationQueryFunction: NodeRelationQueryFunction = nodeCtx => { - const entity = nodeCtx.entity; - const query: EntityRelationsQuery = { - parameters: { - rootId: entity.id.id, - rootType: entity.id.entityType as EntityType, - direction: EntitySearchDirection.FROM, - relationTypeGroup: RelationTypeGroup.COMMON, - maxLevel: 1 - }, - filters: [ - { - relationType: 'Contains', - entityTypes: [] - } - ] - }; - return query; -}; - export const edgeGroupsTypes: EntityType[] = [ EntityType.ASSET, EntityType.DEVICE, @@ -184,71 +88,20 @@ export const edgeGroupsTypes: EntityType[] = [ EntityType.RULE_CHAIN ] -export const defaultNodeIconFunction: NodeIconFunction = nodeCtx => { - let materialIcon = 'insert_drive_file'; - const entity = nodeCtx.entity; - if (entity && entity.id && entity.id.entityType) { - switch (entity.id.entityType as EntityType | string) { - case 'function': - materialIcon = 'functions'; - break; - case EntityType.DEVICE: - materialIcon = 'devices_other'; - break; - case EntityType.ASSET: - materialIcon = 'domain'; - break; - case EntityType.TENANT: - materialIcon = 'supervisor_account'; - break; - case EntityType.CUSTOMER: - materialIcon = 'supervisor_account'; - break; - case EntityType.USER: - materialIcon = 'account_circle'; - break; - case EntityType.DASHBOARD: - materialIcon = 'dashboards'; - break; - case EntityType.ALARM: - materialIcon = 'notifications_active'; - break; - case EntityType.ENTITY_VIEW: - materialIcon = 'view_quilt'; - break; - } - } - return { - materialIcon - }; -}; - -export const defaultNodeOpenedFunction: NodeOpenedFunction = nodeCtx => { - return nodeCtx.level <= 4; -}; - -export const defaultNodesSortFunction: NodesSortFunction = (nodeCtx1, nodeCtx2) => { - let result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType); - if (result === 0) { - result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name); - } - return result; -}; - export interface EdgeOverviewNode extends NavTreeNode { data?: EdgeOverviewNodeData; } -export type EdgeOverviewNodeData = EdgeGroupsNodeData | EdgeNodeData; +export type EdgeOverviewNodeData = EdgeGroupNodeData | EntityNodeData; -export interface EdgeGroupsNodeData extends BaseEdgeOverviewNodeData { - type: 'edgeGroups'; +export interface EdgeGroupNodeData extends BaseEdgeOverviewNodeData { + type: 'edgeGroup'; entityType: EntityType; edge: Edge; } -export interface EdgeNodeData extends BaseEdgeOverviewNodeData { - type: 'edge'; +export interface EntityNodeData extends BaseEdgeOverviewNodeData { + type: 'entity'; entity: Edge; } @@ -257,4 +110,4 @@ export interface BaseEdgeOverviewNodeData { internalId: string; } -export type EdgeOverviewNodeType = 'edge' | 'edgeGroups'; +export type EdgeOverviewNodeType = 'entity' | 'edgeGroup';