Showing
4 changed files
with
40 additions
and
130 deletions
1 | 1 | { |
2 | 2 | "widgetsBundle": { |
3 | 3 | "alias": "edges_widgets", |
4 | - "title": "Edge Instances widgets", | |
4 | + "title": "Edge widgets", | |
5 | 5 | "image": null |
6 | 6 | }, |
7 | 7 | "widgetTypes": [ |
8 | 8 | { |
9 | 9 | "alias": "edges_overview", |
10 | - "name": "Edge Instances Overview", | |
10 | + "name": "Edges Quick Overview", | |
11 | 11 | "descriptor": { |
12 | - "type": "static", | |
12 | + "type": "latest", | |
13 | 13 | "sizeX": 7.5, |
14 | 14 | "sizeY": 5, |
15 | 15 | "resources": [], |
... | ... | @@ -18,7 +18,7 @@ |
18 | 18 | "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", |
19 | 19 | "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}", |
20 | 20 | "dataKeySettingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"DataKeySettings\",\n \"properties\": {},\n \"required\": []\n },\n \"form\": []\n}", |
21 | - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"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 += \\\" <b>\\\"+ data['temperature'] +\\\" °C</b>\\\";\\n}\\nreturn text;\\n\\n**/\",\"nodeIconFunction\":\"/** \\n\\n// Function should return node icon info object.\\n// Resulting object should contain either 'materialIcon' or 'iconUrl' property. \\n// Where:\\n - 'materialIcon' - name of the material icon to be used from the Material Icons Library (https://material.io/tools/icons);\\n - 'iconUrl' - url of the external image to be used as node icon.\\n// Function can return 'default' string value. In this case default icons according to entity type will be used.\\n\\n// The following example code shows how to use external image for devices which name starts with 'Test' and use \\n// default icons for the rest of entities.\\n\\nvar entity = nodeCtx.entity;\\nif (entity.id.entityType === 'DEVICE' && entity.name.startsWith('Test')) {\\n return {iconUrl: 'https://avatars1.githubusercontent.com/u/14793288?v=4&s=117'};\\n} else {\\n return 'default';\\n}\\n \\n**/\",\"nodeDisabledFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be disabled (not selectable).\\n\\n// The following example code will disable current node according to the value of example 'nodeDisabled' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeDisabled') && data['nodeDisabled'] !== null) {\\n return data['nodeDisabled'] === 'true';\\n} else {\\n return false;\\n}\\n \\n**/\\n\",\"nodesSortFunction\":\"/**\\n\\n// This function is used to sort nodes of the same level. Function should compare two nodes and return \\n// integer value: \\n// - less than 0 - sort nodeCtx1 to an index lower than nodeCtx2\\n// - 0 - leave nodeCtx1 and nodeCtx2 unchanged with respect to each other\\n// - greater than 0 - sort nodeCtx2 to an index lower than nodeCtx1\\n\\n// The following example code will sort entities first by entity type in alphabetical order then\\n// by entity name in alphabetical order.\\n\\nvar result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);\\nif (result === 0) {\\n result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name);\\n}\\nreturn result;\\n \\n**/\",\"nodeOpenedFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be opened (expanded) when it first loaded.\\n\\n// The following example code will open by default nodes up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n**/\\n \"},\"title\":\"Edge Instances 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\":{}}" | |
21 | + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"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 += \\\" <b>\\\"+ data['temperature'] +\\\" °C</b>\\\";\\n}\\nreturn text;\\n\\n**/\",\"nodeIconFunction\":\"/** \\n\\n// Function should return node icon info object.\\n// Resulting object should contain either 'materialIcon' or 'iconUrl' property. \\n// Where:\\n - 'materialIcon' - name of the material icon to be used from the Material Icons Library (https://material.io/tools/icons);\\n - 'iconUrl' - url of the external image to be used as node icon.\\n// Function can return 'default' string value. In this case default icons according to entity type will be used.\\n\\n// The following example code shows how to use external image for devices which name starts with 'Test' and use \\n// default icons for the rest of entities.\\n\\nvar entity = nodeCtx.entity;\\nif (entity.id.entityType === 'DEVICE' && entity.name.startsWith('Test')) {\\n return {iconUrl: 'https://avatars1.githubusercontent.com/u/14793288?v=4&s=117'};\\n} else {\\n return 'default';\\n}\\n \\n**/\",\"nodeDisabledFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be disabled (not selectable).\\n\\n// The following example code will disable current node according to the value of example 'nodeDisabled' attribute.\\n\\nvar data = nodeCtx.data;\\nif (data.hasOwnProperty('nodeDisabled') && data['nodeDisabled'] !== null) {\\n return data['nodeDisabled'] === 'true';\\n} else {\\n return false;\\n}\\n \\n**/\\n\",\"nodesSortFunction\":\"/**\\n\\n// This function is used to sort nodes of the same level. Function should compare two nodes and return \\n// integer value: \\n// - less than 0 - sort nodeCtx1 to an index lower than nodeCtx2\\n// - 0 - leave nodeCtx1 and nodeCtx2 unchanged with respect to each other\\n// - greater than 0 - sort nodeCtx2 to an index lower than nodeCtx1\\n\\n// The following example code will sort entities first by entity type in alphabetical order then\\n// by entity name in alphabetical order.\\n\\nvar result = nodeCtx1.entity.id.entityType.localeCompare(nodeCtx2.entity.id.entityType);\\nif (result === 0) {\\n result = nodeCtx1.entity.name.localeCompare(nodeCtx2.entity.name);\\n}\\nreturn result;\\n \\n**/\",\"nodeOpenedFunction\":\"/**\\n\\n// Function should return boolean value indicating whether current node should be opened (expanded) when it first loaded.\\n\\n// The following example code will open by default nodes up to third level.\\n\\nreturn nodeCtx.level <= 2;\\n\\n**/\\n \"},\"title\":\"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\":{}}" | |
22 | 22 | } |
23 | 23 | } |
24 | 24 | ] | ... | ... |
... | ... | @@ -37,6 +37,9 @@ |
37 | 37 | </button> |
38 | 38 | </div> |
39 | 39 | </mat-toolbar> |
40 | + <div *ngIf="customerTitle" fxLayout="row" class="customer-info"> | |
41 | + <span>{{ customerTitle }}</span> | |
42 | + </div> | |
40 | 43 | <div fxFlex class="tb-entities-nav-tree-panel"> |
41 | 44 | <tb-nav-tree |
42 | 45 | [loadNodes]="loadNodes" | ... | ... |
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | /// limitations under the License. |
15 | 15 | /// |
16 | 16 | |
17 | -import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; | |
17 | +import { ChangeDetectorRef, AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; | |
18 | 18 | import { PageComponent } from '@shared/components/page.component'; |
19 | 19 | import { Store } from '@ngrx/store'; |
20 | 20 | import { AppState } from '@core/core.state'; |
... | ... | @@ -23,8 +23,8 @@ import { DatasourceData, DatasourceType, WidgetConfig, widgetType } from '@share |
23 | 23 | import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; |
24 | 24 | import { UtilsService } from '@core/services/utils.service'; |
25 | 25 | import cssjs from '@core/css/css'; |
26 | -import { fromEvent } from 'rxjs'; | |
27 | -import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; | |
26 | +import { fromEvent, Observable } from 'rxjs'; | |
27 | +import { debounceTime, distinctUntilChanged, map, mergeMap, tap } from 'rxjs/operators'; | |
28 | 28 | import { constructTableCssString } from '@home/components/widget/lib/table-widget.models'; |
29 | 29 | import { Overlay } from '@angular/cdk/overlay'; |
30 | 30 | import { |
... | ... | @@ -71,6 +71,8 @@ import { TranslateService } from "@ngx-translate/core"; |
71 | 71 | import { Direction, SortOrder } from "@shared/models/page/sort-order"; |
72 | 72 | import { PageLink } from "@shared/models/page/page-link"; |
73 | 73 | import { Edge, EdgeInfo } from "@shared/models/edge.models"; |
74 | +import { BaseData } from "@shared/models/base-data"; | |
75 | +import { EntityId } from "@shared/models/id/entity-id"; | |
74 | 76 | |
75 | 77 | @Component({ |
76 | 78 | selector: 'tb-edges-overview-widget', |
... | ... | @@ -88,12 +90,15 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
88 | 90 | |
89 | 91 | public textSearchMode = false; |
90 | 92 | public textSearch = null; |
93 | + public customerTitle: string = null; | |
91 | 94 | |
92 | 95 | public nodeEditCallbacks: NavTreeEditCallbacks = {}; |
93 | 96 | |
94 | 97 | private settings: EdgesOverviewWidgetSettings; |
95 | 98 | private widgetConfig: WidgetConfig; |
96 | 99 | private subscription: IWidgetSubscription; |
100 | + private datasources: Array<HierarchyNodeDatasource>; | |
101 | + private data: Array<Array<DatasourceData>>; | |
97 | 102 | |
98 | 103 | private nodesMap: {[nodeId: string]: HierarchyNavTreeNode} = {}; |
99 | 104 | private pendingUpdateNodeTasks: {[nodeId: string]: () => void} = {}; |
... | ... | @@ -113,7 +118,7 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
113 | 118 | |
114 | 119 | private searchAction: WidgetAction = { |
115 | 120 | name: 'action.search', |
116 | - show: true, | |
121 | + show: false, | |
117 | 122 | icon: 'search', |
118 | 123 | onAction: () => { |
119 | 124 | this.enterFilterMode(); |
... | ... | @@ -127,7 +132,8 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
127 | 132 | private translateService: TranslateService, |
128 | 133 | private overlay: Overlay, |
129 | 134 | private viewContainerRef: ViewContainerRef, |
130 | - private utils: UtilsService) { | |
135 | + private utils: UtilsService, | |
136 | + private cd: ChangeDetectorRef) { | |
131 | 137 | super(store); |
132 | 138 | } |
133 | 139 | |
... | ... | @@ -136,6 +142,10 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
136 | 142 | this.settings = this.ctx.settings; |
137 | 143 | this.widgetConfig = this.ctx.widgetConfig; |
138 | 144 | this.subscription = this.ctx.defaultSubscription; |
145 | + this.datasources = this.subscription.datasources as Array<HierarchyNodeDatasource>; | |
146 | + this.data = this.subscription.dataPages[0].data; | |
147 | + this.ctx.widgetTitle = this.datasources[0].entity.name; | |
148 | + this.getCustomerTitle(this.datasources[0].entity.id.id); | |
139 | 149 | this.initializeConfig(); |
140 | 150 | this.ctx.updateWidgetParams(); |
141 | 151 | } |
... | ... | @@ -265,16 +275,10 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
265 | 275 | |
266 | 276 | public loadNodes: LoadNodesCallback = (node, cb) => { |
267 | 277 | if (node.id === '#') { |
268 | - const sortOrder: SortOrder = { property: 'name', direction: Direction.ASC }; | |
269 | - const pageLink = new PageLink(100, 0, null, sortOrder); | |
270 | - this.edgeService.getTenantEdgeInfos(pageLink).subscribe( | |
271 | - (edges) => { | |
272 | - cb(this.edgesToNodes(node.id, edges.data)) | |
273 | - }); | |
274 | - } else if (node.data.type === 'edge') { | |
275 | - const edge = node.data.entity; | |
276 | - cb(this.loadNodesForEdge(node.id, edge)); | |
277 | - } else if (node.data.type === 'edgeGroups') { | |
278 | + const edge: BaseData<EntityId> = this.datasources[0].entity; | |
279 | + cb(this.loadNodesForEdge(edge.id.id, edge)); | |
280 | + } | |
281 | + else if (node.data.type === 'edgeGroups') { | |
278 | 282 | const pageLink = new PageLink(100); |
279 | 283 | this.entityService.getAssignedToEdgeEntitiesByType(node, pageLink).subscribe( |
280 | 284 | (entities) => { |
... | ... | @@ -288,7 +292,7 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
288 | 292 | } |
289 | 293 | } |
290 | 294 | |
291 | - private loadNodesForEdge(parentNodeId: string, edge: EdgeInfo): EdgeOverviewNode[] { | |
295 | + private loadNodesForEdge(parentNodeId: string, edge: any): EdgeOverviewNode[] { | |
292 | 296 | const nodes: EdgeOverviewNode[] = []; |
293 | 297 | const nodesMap = {}; |
294 | 298 | this.edgeGroupsNodesMap[parentNodeId] = nodesMap; |
... | ... | @@ -408,12 +412,6 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
408 | 412 | } |
409 | 413 | } |
410 | 414 | |
411 | - private prepareNodes(nodes: HierarchyNavTreeNode[]): HierarchyNavTreeNode[] { | |
412 | - nodes = nodes.filter((node) => node !== null); | |
413 | - nodes.sort((node1, node2) => this.nodesSortFunction(node1.data.nodeCtx, node2.data.nodeCtx)); | |
414 | - return nodes; | |
415 | - } | |
416 | - | |
417 | 415 | private prepareNodeText(node: HierarchyNavTreeNode): string { |
418 | 416 | const nodeIcon = this.prepareNodeIcon(node.data.nodeCtx); |
419 | 417 | const nodeText = this.nodeTextFunction(node.data.nodeCtx); |
... | ... | @@ -441,110 +439,15 @@ export class EdgesOverviewWidgetComponent extends PageComponent implements OnIni |
441 | 439 | } |
442 | 440 | } |
443 | 441 | |
444 | - private datasourceToNode(datasource: HierarchyNodeDatasource, | |
445 | - data: DatasourceData[], | |
446 | - parentNodeCtx?: HierarchyNodeContext): HierarchyNavTreeNode { | |
447 | - const node: HierarchyNavTreeNode = { | |
448 | - id: (++this.nodeIdCounter) + '' | |
449 | - }; | |
450 | - this.nodesMap[node.id] = node; | |
451 | - datasource.nodeId = node.id; | |
452 | - node.icon = false; | |
453 | - const nodeCtx: HierarchyNodeContext = { | |
454 | - parentNodeCtx, | |
455 | - entity: { | |
456 | - id: { | |
457 | - id: datasource.entityId, | |
458 | - entityType: datasource.entityType | |
459 | - }, | |
460 | - name: datasource.entityName, | |
461 | - label: datasource.entityLabel ? datasource.entityLabel : datasource.entityName | |
462 | - }, | |
463 | - data: {} | |
464 | - }; | |
465 | - datasource.dataKeys.forEach((dataKey, index) => { | |
466 | - const keyData = data[index].data; | |
467 | - if (keyData && keyData.length && keyData[0].length > 1) { | |
468 | - nodeCtx.data[dataKey.label] = keyData[0][1]; | |
469 | - } else { | |
470 | - nodeCtx.data[dataKey.label] = ''; | |
471 | - } | |
472 | - }); | |
473 | - nodeCtx.level = parentNodeCtx ? parentNodeCtx.level + 1 : 1; | |
474 | - node.data = { | |
475 | - datasource, | |
476 | - nodeCtx | |
477 | - }; | |
478 | - node.state = { | |
479 | - disabled: this.nodeDisabledFunction(node.data.nodeCtx), | |
480 | - opened: this.nodeOpenedFunction(node.data.nodeCtx) | |
481 | - }; | |
482 | - node.text = this.prepareNodeText(node); | |
483 | - node.children = this.nodeHasChildrenFunction(node.data.nodeCtx); | |
484 | - return node; | |
485 | - } | |
486 | - | |
487 | - private loadChildren(parentNode: HierarchyNavTreeNode, datasource: HierarchyNodeDatasource, childrenNodesLoadCb: NodesCallback) { | |
488 | - const nodeCtx = parentNode.data.nodeCtx; | |
489 | - nodeCtx.childrenNodesLoaded = false; | |
490 | - const entityFilter = this.prepareNodeRelationsQueryFilter(nodeCtx); | |
491 | - const childrenDatasource = { | |
492 | - dataKeys: datasource.dataKeys, | |
493 | - type: DatasourceType.entity, | |
494 | - filterId: datasource.filterId, | |
495 | - entityFilter | |
496 | - } as HierarchyNodeDatasource; | |
497 | - const subscriptionOptions: WidgetSubscriptionOptions = { | |
498 | - type: widgetType.latest, | |
499 | - datasources: [childrenDatasource], | |
500 | - callbacks: { | |
501 | - onSubscriptionMessage: (subscription, message) => { | |
502 | - this.ctx.showToast(message.severity, message.message, undefined, | |
503 | - 'bottom', 'left', this.toastTargetId); | |
504 | - }, | |
505 | - onInitialPageDataChanged: (subscription) => { | |
506 | - this.ctx.subscriptionApi.removeSubscription(subscription.id); | |
507 | - this.nodeEditCallbacks.refreshNode(parentNode.id); | |
508 | - }, | |
509 | - onDataUpdated: subscription => { | |
510 | - if (nodeCtx.childrenNodesLoaded) { | |
511 | - this.updateNodeData(subscription.data); | |
512 | - } else { | |
513 | - const datasourcesPageData = subscription.datasourcePages[0]; | |
514 | - const dataPageData = subscription.dataPages[0]; | |
515 | - const childNodes: HierarchyNavTreeNode[] = []; | |
516 | - datasourcesPageData.data.forEach((childDatasource, index) => { | |
517 | - childNodes.push(this.datasourceToNode(childDatasource as HierarchyNodeDatasource, dataPageData.data[index])); | |
518 | - }); | |
519 | - nodeCtx.childrenNodesLoaded = true; | |
520 | - childrenNodesLoadCb(this.prepareNodes(childNodes)); | |
521 | - } | |
442 | + private getCustomerTitle(edgeId) { | |
443 | + this.edgeService.getEdgeInfo(edgeId).subscribe( | |
444 | + (edge) => { | |
445 | + if (edge.customerTitle) { | |
446 | + this.customerTitle = this.translateService.instant('edge.assigned-to-customer') + ': ' + edge.customerTitle; | |
447 | + } else { | |
448 | + this.customerTitle = null; | |
522 | 449 | } |
523 | - } | |
524 | - }; | |
525 | - this.ctx.subscriptionApi.createSubscription(subscriptionOptions, true); | |
526 | - } | |
527 | - | |
528 | - private prepareNodeRelationQuery(nodeCtx: HierarchyNodeContext): EntityRelationsQuery { | |
529 | - let relationQuery = this.nodeRelationQueryFunction(nodeCtx); | |
530 | - if (relationQuery && relationQuery === 'default') { | |
531 | - relationQuery = defaultNodeRelationQueryFunction(nodeCtx); | |
532 | - } | |
533 | - return relationQuery as EntityRelationsQuery; | |
534 | - } | |
535 | - | |
536 | - private prepareNodeRelationsQueryFilter(nodeCtx: HierarchyNodeContext): EntityFilter { | |
537 | - const relationQuery = this.prepareNodeRelationQuery(nodeCtx); | |
538 | - return { | |
539 | - rootEntity: { | |
540 | - id: relationQuery.parameters.rootId, | |
541 | - entityType: relationQuery.parameters.rootType | |
542 | - }, | |
543 | - direction: relationQuery.parameters.direction, | |
544 | - filters: relationQuery.filters, | |
545 | - maxLevel: relationQuery.parameters.maxLevel, | |
546 | - fetchLastLevelOnly: relationQuery.parameters.fetchLastLevelOnly, | |
547 | - type: AliasFilterType.relationsQuery | |
548 | - } as RelationsQueryFilter; | |
450 | + this.cd.detectChanges(); | |
451 | + }); | |
549 | 452 | } |
550 | 453 | } | ... | ... |