198 lines
7.3 KiB
TypeScript
198 lines
7.3 KiB
TypeScript
import {IPersistenceManager} from "../iPersistenceManager";
|
|
import {
|
|
AbstractMesh,
|
|
Color3,
|
|
DynamicTexture,
|
|
InstancedMesh,
|
|
MeshBuilder,
|
|
Scene,
|
|
StandardMaterial,
|
|
Vector3
|
|
} from "@babylonjs/core";
|
|
|
|
export class NewRelicData {
|
|
private key: string;
|
|
private account: string;
|
|
private data: any[];
|
|
private readonly scene: Scene;
|
|
private persistenceManager: IPersistenceManager;
|
|
private policyLabels: AbstractMesh[] = [];
|
|
|
|
constructor(persistenceManager: IPersistenceManager, scene: Scene) {
|
|
this.persistenceManager = persistenceManager;
|
|
this.scene = scene;
|
|
this.persistenceManager.getNewRelicData()
|
|
.then((data) => {
|
|
this.data = data;
|
|
this.getNewRelicData().then(() => {
|
|
this.drawGraph();
|
|
});
|
|
});
|
|
}
|
|
|
|
public setCredentials(key: string, account: string) {
|
|
this.key = key;
|
|
this.account = account;
|
|
}
|
|
|
|
public async clearData() {
|
|
this.data = [];
|
|
await this.persistenceManager.setNewRelicData(this.data);
|
|
}
|
|
|
|
public async getNewRelicData() {
|
|
if (this.data && this.data.length > 0) {
|
|
console.warn("Already have data, early return");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('https://deepdiagram.com/.netlify/functions/nerdgraph', {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
body: '{"query": "{actor { nrql(query: \\"select * from NrAiIncident \\", accounts: ' + this.account + ') { results } } }"}',
|
|
headers: {"Api-Key": this.key}
|
|
});
|
|
const data = await res.json();
|
|
if (data?.data?.actor?.nrql?.results) {
|
|
const newdata = data.data.actor.nrql.results.map((item: any) => {
|
|
item.id = item.incidentId;
|
|
item.policyName = item.policyName ? item.policyName : "No Policy";
|
|
return item
|
|
});
|
|
await this.persistenceManager.setNewRelicData(newdata);
|
|
this.data = newdata;
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public drawGraph() {
|
|
this.data.sort((a, b) => {
|
|
return parseInt(a.openTime) - parseInt(b.openTime);
|
|
});
|
|
|
|
const duration = this.data[this.data.length - 1].openTime - this.data[0].openTime;
|
|
const interval = 10 / duration;
|
|
const first = parseInt(this.data[0].openTime);
|
|
const material = new StandardMaterial("material", this.scene);
|
|
material.diffuseColor = new Color3(0, 0, .7);
|
|
material.alpha = .3;
|
|
const baseMesh = MeshBuilder.CreateBox("baseItem", {width: 1, height: 1, depth: 1}, this.scene);
|
|
baseMesh.material = material;
|
|
|
|
const warningMaterial = new StandardMaterial("warningMaterial", this.scene);
|
|
warningMaterial.diffuseColor = new Color3(.7, .7, .2);
|
|
warningMaterial.alpha = .5;
|
|
const warningMesh = MeshBuilder.CreateBox("warningItem", {width: 1, height: 1, depth: 1}, this.scene);
|
|
warningMesh.material = warningMaterial;
|
|
|
|
const criticalMaterial = new StandardMaterial("criticalMaterial", this.scene);
|
|
criticalMaterial.diffuseColor = new Color3(.9, .2, .2);
|
|
criticalMaterial.alpha = .7;
|
|
const criticalMesh = MeshBuilder.CreateBox("criticalItem", {width: 1, height: 1, depth: 1}, this.scene);
|
|
criticalMesh.material = criticalMaterial;
|
|
|
|
|
|
const policies: Map<String, { x: number, y: number }> = new Map<string, { x: number, y: number }>();
|
|
this.data.forEach((item) => {
|
|
const policy = item.policyName ? item.policyName : "No Policy";
|
|
let x;
|
|
let y: number = 0;
|
|
if (policies.has(policy)) {
|
|
const value = policies.get(policy);
|
|
x = value.x;
|
|
y = value.y + .105;
|
|
policies.set(policy, {x, y});
|
|
} else {
|
|
policies.set(policy, {x: policies.size / 10, y: 0});
|
|
x = policies.get(policy).x;
|
|
const policyLabel = this.buildText(policy);
|
|
policyLabel.scaling = new Vector3(3, 3, 3);
|
|
policyLabel.position = new Vector3(x, .4, 0);
|
|
policyLabel.rotation.x = Math.PI / 2;
|
|
policyLabel.rotation.y = -Math.PI / 2;
|
|
|
|
this.policyLabels.push(policyLabel);
|
|
}
|
|
const start = parseInt(item.openTime) - first;
|
|
let end = duration;
|
|
if (item.closeTime) {
|
|
end = parseInt(item.closeTime) - first;
|
|
}
|
|
let box: AbstractMesh;
|
|
switch (item.priority) {
|
|
case "critical":
|
|
box = new InstancedMesh(item.id, criticalMesh);
|
|
break;
|
|
case "warning":
|
|
box = new InstancedMesh(item.id, warningMesh);
|
|
break;
|
|
default:
|
|
box = new InstancedMesh(item.id, baseMesh);
|
|
}
|
|
|
|
box.position = new Vector3(x, y + .5, (start * interval));
|
|
if (item.closeTime) {
|
|
box.scaling = new Vector3(.1, .1, (end - start) * interval);
|
|
} else {
|
|
box.scaling = new Vector3(.1, .1, .01);
|
|
}
|
|
box.position.z = box.position.z + box.scaling.z / 2;
|
|
|
|
const startLabel = this.buildText(new Date(start + first).toLocaleString());
|
|
startLabel.position = box.position.add(new Vector3(.05, .05, 0));
|
|
startLabel.position.z = (start * interval) - .01;
|
|
|
|
const endLabel = this.buildText(new Date(end + first).toLocaleString());
|
|
endLabel.position = box.position.add(new Vector3(.05, .05, 0));
|
|
endLabel.position.z = (end * interval) + .01;
|
|
|
|
});
|
|
|
|
this.scene.onBeforeRenderObservable.add(() => {
|
|
this.policyLabels.forEach((label) => {
|
|
label.position.z = this.scene.activeCamera.globalPosition.z;
|
|
});
|
|
});
|
|
}
|
|
|
|
private buildText(text: string) {
|
|
//Set font
|
|
const height = 0.03;
|
|
const font_size = 24;
|
|
const font = "bold " + font_size + "px Arial";
|
|
//Set height for dynamic texture
|
|
const DTHeight = 1.5 * font_size; //or set as wished
|
|
//Calc Ratio
|
|
const ratio = height / DTHeight;
|
|
|
|
//Use a temporary dynamic texture to calculate the length of the text on the dynamic texture canvas
|
|
const temp = new DynamicTexture("DynamicTexture", 32, this.scene);
|
|
const tmpctx = temp.getContext();
|
|
tmpctx.font = font;
|
|
const DTWidth = tmpctx.measureText(text).width + 8;
|
|
|
|
//Calculate width the plane has to be
|
|
const planeWidth = DTWidth * ratio;
|
|
|
|
//Create dynamic texture and write the text
|
|
const dynamicTexture = new DynamicTexture("DynamicTexture", {
|
|
width: DTWidth,
|
|
height: DTHeight
|
|
}, this.scene, false);
|
|
const mat = new StandardMaterial("mat", this.scene);
|
|
mat.diffuseTexture = dynamicTexture;
|
|
dynamicTexture.drawText(text, null, null, font, "#000000", "#ffffff", true);
|
|
|
|
//Create plane and set dynamic texture as material
|
|
const plane = MeshBuilder.CreatePlane("text", {width: planeWidth, height: height}, this.scene);
|
|
|
|
plane.material = mat;
|
|
|
|
return plane;
|
|
}
|
|
} |