1import { 2 ArrayVector, 3 FieldColorModeId, 4 FieldDTO, 5 FieldType, 6 MutableDataFrame, 7 NodeGraphDataFrameFieldNames, 8} from '@grafana/data'; 9import { nodes, edges } from './testData/serviceMapResponse'; 10 11export function generateRandomNodes(count = 10) { 12 const nodes = []; 13 14 const root = { 15 id: '0', 16 title: 'root', 17 subTitle: 'client', 18 success: 1, 19 error: 0, 20 stat1: Math.random(), 21 stat2: Math.random(), 22 edges: [] as any[], 23 }; 24 nodes.push(root); 25 const nodesWithoutMaxEdges = [root]; 26 27 const maxEdges = 3; 28 29 for (let i = 1; i < count; i++) { 30 const node = makeRandomNode(i); 31 nodes.push(node); 32 const sourceIndex = Math.floor(Math.random() * Math.floor(nodesWithoutMaxEdges.length - 1)); 33 const source = nodesWithoutMaxEdges[sourceIndex]; 34 source.edges.push(node.id); 35 if (source.edges.length >= maxEdges) { 36 nodesWithoutMaxEdges.splice(sourceIndex, 1); 37 } 38 nodesWithoutMaxEdges.push(node); 39 } 40 41 // Add some random edges to create possible cycle 42 const additionalEdges = Math.floor(count / 2); 43 for (let i = 0; i <= additionalEdges; i++) { 44 const sourceIndex = Math.floor(Math.random() * Math.floor(nodes.length - 1)); 45 const targetIndex = Math.floor(Math.random() * Math.floor(nodes.length - 1)); 46 if (sourceIndex === targetIndex || nodes[sourceIndex].id === '0' || nodes[sourceIndex].id === '0') { 47 continue; 48 } 49 50 nodes[sourceIndex].edges.push(nodes[sourceIndex].id); 51 } 52 53 const nodeFields: Record<string, Omit<FieldDTO, 'name'> & { values: ArrayVector }> = { 54 [NodeGraphDataFrameFieldNames.id]: { 55 values: new ArrayVector(), 56 type: FieldType.string, 57 }, 58 [NodeGraphDataFrameFieldNames.title]: { 59 values: new ArrayVector(), 60 type: FieldType.string, 61 }, 62 [NodeGraphDataFrameFieldNames.subTitle]: { 63 values: new ArrayVector(), 64 type: FieldType.string, 65 }, 66 [NodeGraphDataFrameFieldNames.mainStat]: { 67 values: new ArrayVector(), 68 type: FieldType.number, 69 config: { displayName: 'Transactions per second' }, 70 }, 71 [NodeGraphDataFrameFieldNames.secondaryStat]: { 72 values: new ArrayVector(), 73 type: FieldType.number, 74 config: { displayName: 'Average duration' }, 75 }, 76 [NodeGraphDataFrameFieldNames.arc + 'success']: { 77 values: new ArrayVector(), 78 type: FieldType.number, 79 config: { color: { fixedColor: 'green', mode: FieldColorModeId.Fixed }, displayName: 'Success' }, 80 }, 81 [NodeGraphDataFrameFieldNames.arc + 'errors']: { 82 values: new ArrayVector(), 83 type: FieldType.number, 84 config: { color: { fixedColor: 'red', mode: FieldColorModeId.Fixed }, displayName: 'Errors' }, 85 }, 86 }; 87 88 const nodeFrame = new MutableDataFrame({ 89 name: 'nodes', 90 fields: Object.keys(nodeFields).map((key) => ({ 91 ...nodeFields[key], 92 name: key, 93 })), 94 meta: { preferredVisualisationType: 'nodeGraph' }, 95 }); 96 97 const edgeFields: any = { 98 [NodeGraphDataFrameFieldNames.id]: { 99 values: new ArrayVector(), 100 type: FieldType.string, 101 }, 102 [NodeGraphDataFrameFieldNames.source]: { 103 values: new ArrayVector(), 104 type: FieldType.string, 105 }, 106 [NodeGraphDataFrameFieldNames.target]: { 107 values: new ArrayVector(), 108 type: FieldType.string, 109 }, 110 }; 111 112 const edgesFrame = new MutableDataFrame({ 113 name: 'edges', 114 fields: Object.keys(edgeFields).map((key) => ({ 115 ...edgeFields[key], 116 name: key, 117 })), 118 meta: { preferredVisualisationType: 'nodeGraph' }, 119 }); 120 121 const edgesSet = new Set(); 122 for (const node of nodes) { 123 nodeFields.id.values.add(node.id); 124 nodeFields.title.values.add(node.title); 125 nodeFields.subTitle.values.add(node.subTitle); 126 nodeFields.mainStat.values.add(node.stat1); 127 nodeFields.secondaryStat.values.add(node.stat2); 128 nodeFields.arc__success.values.add(node.success); 129 nodeFields.arc__errors.values.add(node.error); 130 for (const edge of node.edges) { 131 const id = `${node.id}--${edge}`; 132 // We can have duplicate edges when we added some more by random 133 if (edgesSet.has(id)) { 134 continue; 135 } 136 edgesSet.add(id); 137 edgeFields.id.values.add(`${node.id}--${edge}`); 138 edgeFields.source.values.add(node.id); 139 edgeFields.target.values.add(edge); 140 } 141 } 142 143 return [nodeFrame, edgesFrame]; 144} 145 146function makeRandomNode(index: number) { 147 const success = Math.random(); 148 const error = 1 - success; 149 return { 150 id: index.toString(), 151 title: `service:${index}`, 152 subTitle: 'service', 153 success, 154 error, 155 stat1: Math.random(), 156 stat2: Math.random(), 157 edges: [], 158 }; 159} 160 161export function savedNodesResponse(): any { 162 return [new MutableDataFrame(nodes), new MutableDataFrame(edges)]; 163} 164