Compare commits

..

No commits in common. "584cb237fe5f25ce737878b36a6e4b4751147606" and "a010112f39f81cf2628a40e3b32d949db21eeece" have entirely different histories.

5 changed files with 15 additions and 150 deletions

View File

@ -64,7 +64,6 @@ async fn main() -> anyhow::Result<()> {
let router = Router::new() let router = Router::new()
// JSON api endpoints // JSON api endpoints
.nest("/js", routes::mk_js_routes(config.clone())) .nest("/js", routes::mk_js_routes(config.clone()))
.nest("/static", routes::mk_static_routes(config.clone()))
.nest("/api", routes::mk_api_routes(config.clone())) .nest("/api", routes::mk_api_routes(config.clone()))
// HTMX ui component endpoints // HTMX ui component endpoints
.nest("/ui", routes::mk_ui_routes(config.clone())) .nest("/ui", routes::mk_ui_routes(config.clone()))

View File

@ -21,20 +21,18 @@ use prometheus_http_query::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::debug; use tracing::debug;
#[derive(Deserialize, Clone, Debug)] #[derive(Deserialize, Clone)]
pub enum QueryType { pub enum QueryType {
Range, Range,
Scalar, Scalar,
} }
#[derive(Debug)]
pub struct TimeSpan { pub struct TimeSpan {
pub end: DateTime<Utc>, pub end: DateTime<Utc>,
pub duration: chrono::Duration, pub duration: chrono::Duration,
pub step_seconds: i64, pub step_seconds: i64,
} }
#[derive(Debug)]
pub struct QueryConn<'conn> { pub struct QueryConn<'conn> {
source: &'conn str, source: &'conn str,
query: &'conn str, query: &'conn str,

View File

@ -115,7 +115,7 @@ pub async fn dash_ui(State(config): State<Config>, Path(dash_idx): Path<usize>)
.collect::<Vec<(usize, &Graph)>>(); .collect::<Vec<(usize, &Graph)>>();
html!( html!(
h1 { (dash.title) } h1 { (dash.title) }
span-selector class="row-flex" {} span-selector {}
@for (idx, graph) in &graph_iter { @for (idx, graph) in &graph_iter {
(graph_component(dash_idx, *idx, *graph)) (graph_component(dash_idx, *idx, *graph))
} }
@ -144,7 +144,6 @@ 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" { }
link rel="stylesheet" href="/static/site.css" { }
(app(State(config.clone())).await) (app(State(config.clone())).await)
} }
} }
@ -158,16 +157,15 @@ pub async fn app(State(config): State<Config>) -> Markup {
.enumerate() .enumerate()
.collect::<Vec<(usize, String)>>(); .collect::<Vec<(usize, String)>>();
html! { html! {
div class="row-flex" { div {
div class="flex-item-shrink" { // Header menu
// Header menu ul {
ul { @for title in &titles {
@for title in &titles { li hx-get=(format!("/ui/dash/{}", title.0)) hx-target="#dashboard" { (title.1) }
li hx-get=(format!("/ui/dash/{}", title.0)) hx-target="#dashboard" { (title.1) }
}
} }
} }
div class="flex-item-grow" id="dashboard" { } // dashboard display
div id="dashboard" { }
} }
} }
} }
@ -199,10 +197,3 @@ pub fn mk_js_routes(config: Arc<Vec<Dashboard>>) -> Router<Config> {
.route("/htmx.js", get(htmx)) .route("/htmx.js", get(htmx))
.with_state(State(config)) .with_state(State(config))
} }
pub fn mk_static_routes(config: Arc<Vec<Dashboard>>) -> Router<Config> {
Router::new()
.route("/site.css", get(|| async { return include_str!("../static/site.css"); }))
.with_state(State(config))
}

View File

@ -12,10 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
function getCssVariableValue(variableName) {
return getComputedStyle(document.documentElement).getPropertyValue(variableName);
}
class TimeseriesGraph extends HTMLElement { class TimeseriesGraph extends HTMLElement {
#uri; #uri;
#width; #width;
@ -37,13 +33,10 @@ class TimeseriesGraph extends HTMLElement {
this.#height = 600; this.#height = 600;
this.#pollSeconds = 30; this.#pollSeconds = 30;
this.#menuContainer = this.appendChild(document.createElement('div')); this.#menuContainer = this.appendChild(document.createElement('div'));
// TODO(jwall): These should probably be done as template clones so we have less places
// to look for class attributes.
this.#menuContainer.setAttribute("class", "row-flex");
this.#targetNode = this.appendChild(document.createElement("div")); this.#targetNode = this.appendChild(document.createElement("div"));
} }
static observedAttributes = ['uri', 'width', 'height', 'poll-seconds', 'end', 'duration', 'step-duration', 'd3-tick-format']; static observedAttributes = ['uri', 'width', 'height', 'poll-seconds', 'end', 'duration', 'step-duration'];
attributeChangedCallback(name, _oldValue, newValue) { attributeChangedCallback(name, _oldValue, newValue) {
switch (name) { switch (name) {
@ -172,9 +165,12 @@ class TimeseriesGraph extends HTMLElement {
} }
buildSelectElement(key) { buildSelectElement(key) {
// TODO(jwall): Should we have a select all?
var id = key + "-select" + Math.random(); var id = key + "-select" + Math.random();
const element = document.createElement("div"); const element = document.createElement("div");
const label = document.createElement("label");
label.innerText = key + ": ";
label.setAttribute("for", id);
element.appendChild(label);
const select = document.createElement("select"); const select = document.createElement("select");
select.setAttribute("name", id); select.setAttribute("name", id);
select.setAttribute("multiple", true); select.setAttribute("multiple", true);
@ -185,7 +181,6 @@ class TimeseriesGraph extends HTMLElement {
for (var opt of this.#filterLabels[key]) { for (var opt of this.#filterLabels[key]) {
const optElement = document.createElement("option"); const optElement = document.createElement("option");
optElement.setAttribute("value", opt); optElement.setAttribute("value", opt);
optElement.setAttribute("selected", true);
optElement.innerText = opt; optElement.innerText = opt;
select.appendChild(optElement); select.appendChild(optElement);
} }
@ -222,12 +217,6 @@ class TimeseriesGraph extends HTMLElement {
this.populateFilterData(labels); this.populateFilterData(labels);
} }
} }
if (subplot.Scalar) {
for (const triple of subplot.Scalar) {
const labels = triple[0];
this.populateFilterData(labels);
}
}
} }
} }
@ -244,14 +233,6 @@ class TimeseriesGraph extends HTMLElement {
var layout = { var layout = {
displayModeBar: false, displayModeBar: false,
responsive: true, responsive: true,
plot_bgcolor: getCssVariableValue('--paper-background-color').trim(),
paper_bgcolor: getCssVariableValue('--paper-background-color').trim(),
font: {
color: getCssVariableValue('--text-color').trim()
},
xaxis: {
gridcolor: getCssVariableValue("--accent-color")
}
}; };
var traces = []; var traces = [];
for (var subplot_idx in data) { for (var subplot_idx in data) {
@ -273,7 +254,6 @@ class TimeseriesGraph extends HTMLElement {
// https://plotly.com/javascript/reference/layout/yaxis/ // https://plotly.com/javascript/reference/layout/yaxis/
layout["yaxis" + subplotCount] = { layout["yaxis" + subplotCount] = {
anchor: yaxis, anchor: yaxis,
gridcolor: getCssVariableValue("--accent-color"),
tickformat: meta["d3_tick_format"] || this.#d3TickFormat tickformat: meta["d3_tick_format"] || this.#d3TickFormat
}; };
const series = triple[2]; const series = triple[2];
@ -297,18 +277,8 @@ class TimeseriesGraph extends HTMLElement {
} }
} else if (subplot.Scalar) { } else if (subplot.Scalar) {
// https://plotly.com/javascript/reference/bar/ // https://plotly.com/javascript/reference/bar/
layout["yaxis"] = { for (const triple of subplot.Scalar) {
tickformat: this.#d3TickFormat,
gridcolor: getCssVariableValue("--accent-color")
};
loopScalar: for (const triple of subplot.Scalar) {
const labels = triple[0]; const labels = triple[0];
for (var label in labels) {
var show = this.#filteredLabelSets[label];
if (show && !show.includes(labels[label])) {
continue loopScalar;
}
}
const meta = triple[1]; const meta = triple[1];
const series = triple[2]; const series = triple[2];
var trace = { var trace = {
@ -358,7 +328,6 @@ class SpanSelector extends HTMLElement {
connectedCallback() { connectedCallback() {
const self = this; const self = this;
// TODO(jwall): We should probably show a loading indicator of some kind.
self.#updateInput.onclick = function(_evt) { self.#updateInput.onclick = function(_evt) {
self.updateGraphs() self.updateGraphs()
}; };

View File

@ -1,92 +0,0 @@
:root {
/* Base colors */
--background-color: #FFFFFF; /* Light background */
--text-color: #333333; /* Dark text for contrast */
--paper-background-color: #F0F0F0;
--accent-color: #6200EE; /* For buttons and interactive elements */
/* Graph colors */
--graph-color-1: #007BFF; /* Blue */
--graph-color-2: #28A745; /* Green */
--graph-color-3: #DC3545; /* Red */
--graph-color-4: #FFC107; /* Yellow */
--graph-color-5: #17A2B8; /* Cyan */
--graph-color-6: #6C757D; /* Gray */
/* Axis and grid lines */
--axis-color: #CCCCCC;
--grid-line-color: #EEEEEE;
/* Tooltip background */
--tooltip-background-color: #FFFFFF;
--tooltip-text-color: #000000;
}
@media (prefers-color-scheme: dark) {
:root {
/* Solarized Dark Base Colors */
--background-color: #002b36; /* base03 */
--paper-background-color: #003c4a;
--text-color: #839496; /* base0 */
--accent-color: #268bd2; /* blue */
/* Graph colors - Solarized Accent Colors */
--graph-color-1: #b58900; /* yellow */
--graph-color-2: #cb4b16; /* orange */
--graph-color-3: #dc322f; /* red */
--graph-color-4: #d33682; /* magenta */
--graph-color-5: #6c71c4; /* violet */
--graph-color-6: #2aa198; /* cyan */
/* Axis and grid lines */
--axis-color: #586e75; /* base01 */
--grid-line-color: #073642; /* base02 */
/* Tooltip background */
--tooltip-background-color: #002b36; /* base03 */
--tooltip-text-color: #839496; /* base0 */
}
}
body {
background-color: var(--background-color);
color: var(--text-color);
}
input, textarea, select, option, button {
background-color: var(--paper-background-color);
border: 1px solid var(--accent-color);
color: var(--text-color);
padding: 8px;
border-radius: 4px;
}
body * {
padding-left: .3em;
padding-right: .3em;
}
.column-flex {
display: flex;
flex-direction: column;
}
.row-flex {
display: flex;
flex-direction: row;
}
.flex-item-grow {
flex: 1 0 auto;
}
.flex-item-shrink {
flex: 0 1 auto;
}
timeseries-graph {
background-color: var(--paper-background-color);
border-radius: 4px;
display: flex;
flex-direction: column;
}