nodeGraphUtils.ts 4.7 KB

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