dev: Encapsulate the graphing bits in a web component

This commit is contained in:
Jeremy Wall 2024-02-08 19:00:41 -06:00
parent 08267f7727
commit 9e52ac341b
3 changed files with 66 additions and 29 deletions

View File

@ -3,15 +3,15 @@
graphs: graphs:
- title: Node cpu - title: Node cpu
source: http://heimdall:9001 source: http://heimdall:9001
query: 'node_cpu_seconds_total{job="nodestats"}' query: 'sum by (instance)(irate(node_cpu_seconds_total{mode="system",job="nodestats"}[5m])) * 100'
- title: Node memory - title: Node memory
source: http://heimdall:9001 source: http://heimdall:9001
query: 'node_memory_MemFree_bytes{instance="andrew:9002",job="nodestats"}' query: 'node_memory_MemFree_bytes{job="nodestats"}'
- title: Test Dasbboard 2 - title: Test Dasbboard 2
graphs: graphs:
- title: Node cpu - title: Node cpu
source: http://heimdall:9001 source: http://heimdall:9001
query: 'node_cpu_seconds_total{job="nodestats"}' query: 'sum by (instance)(irate(node_cpu_seconds_total{mode="system",job="nodestats"}[5m])) * 100'
- title: Node memory - title: Node memory
source: http://heimdall:9001 source: http://heimdall:9001
query: 'node_memory_MemFree_bytes{instance="andrew:9002",job="nodestats"}' query: 'node_memory_MemFree_bytes{,job="nodestats"}'

View File

@ -64,21 +64,10 @@ pub fn mk_api_routes(config: Arc<Vec<Dashboard>>) -> Router<Config> {
pub fn graph_component(dash_idx: usize, graph_idx: usize, graph: &Graph) -> Markup { pub fn graph_component(dash_idx: usize, graph_idx: usize, graph: &Graph) -> Markup {
let graph_id = format!("graph-{}-{}", dash_idx, graph_idx); let graph_id = format!("graph-{}-{}", dash_idx, graph_idx);
let graph_data_uri = format!("/api/dash/{}/graph/{}", dash_idx, graph_idx); let graph_data_uri = format!("/api/dash/{}/graph/{}", dash_idx, graph_idx);
// initialize the plot with Plotly.react
// Update plot with Plotly.react which is more efficient
let script = format!(
"var graph{graph_idx} = new Timeseries('{uri}', '{graph_id}'); graph{graph_idx}.updateGraph();",
uri = graph_data_uri,
graph_id = graph_id,
graph_idx = graph_idx,
);
html!( html!(
div { div {
h2 { (graph.title) } h2 { (graph.title) }
script { timeseries-graph uri=(graph_data_uri) id=(graph_id) { }
(script)
}
div id=(graph_id) { }
} }
) )
} }
@ -134,6 +123,9 @@ pub async fn index(State(config): State<Config>) -> Markup {
script src="/js/plotly.js" { } script src="/js/plotly.js" { }
script src="/js/htmx.js" { } script src="/js/htmx.js" { }
script src="/js/lib.js" { } script src="/js/lib.js" { }
template id="timeseries_template" {
div;
}
(app(State(config.clone())).await) (app(State(config.clone())).await)
} }
} }

View File

@ -1,16 +1,59 @@
class TimeseriesGraph extends HTMLElement {
class Timeseries {
#uri; #uri;
#title; #width;
#targetEl; #height;
//#width; constructor() {
//#height; super();
const root = this.attachShadow({ mode: "open" });
var template = document.getElementById("timeseries_template");
this.#width = 1000;
this.height = 500;
root.appendChild(template.content.cloneNode(true));
}
constructor(uri, targetEl, /** width, height **/) { static observedAttributes = ['uri', 'width', 'height'];
this.#uri = uri;
this.#targetEl = targetEl; attributeChanged(name, _oldValue, newValue) {
//this.#width = width; switch (name) {
//this.#height = height; case 'uri':
this.#uri = newValue;
break;
case 'width':
this.#width = newValue;
break;
case 'height':
this.#height = newValue;
break;
default: // do nothing;
break;
}
this.updateGraph();
// TODO(zaphar): reset update timer as well
}
getTargetNode() {
console.log("shadowroot: ", this.shadowRoot);
return this.shadowRoot.firstChild;
}
connectedCallback() {
// TODO(zaphar): Set up the timer loop to update graph data.
this.#uri = this.getAttribute('uri');
if (this.#uri) {
this.updateGraph();
}
}
disconnectedCallback() {
// TODO(zaphar): Turn off the timer loop to update graph.
}
static elementName = "timeseries-graph";
static registerElement() {
if (!customElements.get(TimeseriesGraph.elementName)) {
customElements.define(TimeseriesGraph.elementName, TimeseriesGraph);
}
} }
async fetchData() { async fetchData() {
@ -39,9 +82,11 @@ class Timeseries {
traces.push(trace); traces.push(trace);
} }
console.log("Traces: ", traces); console.log("Traces: ", traces);
Plotly.react(this.#targetEl, traces, { width: 500, height: 500 }); Plotly.react(this.getTargetNode(), traces, { width: this.#width, height: this.#height });
} else if (data.Scalar) { } else if (data.Scalar) {
// The graph should be a single value // The graph should be a single value
} }
} }
} }
TimeseriesGraph.registerElement();