diff --git a/.sqlx/query-35324f9148e3e7ce2d2aa62d69378ce28a2398b408bbc99ea1299315904d6673.json b/.sqlx/query-35324f9148e3e7ce2d2aa62d69378ce28a2398b408bbc99ea1299315904d6673.json
new file mode 100644
index 0000000..97964f7
--- /dev/null
+++ b/.sqlx/query-35324f9148e3e7ce2d2aa62d69378ce28a2398b408bbc99ea1299315904d6673.json
@@ -0,0 +1,20 @@
+{
+ "db_name": "SQLite",
+ "query": "SELECT DISTINCT metric FROM run_measurements ORDER BY metric ASC",
+ "describe": {
+ "columns": [
+ {
+ "name": "metric",
+ "ordinal": 0,
+ "type_info": "Text"
+ }
+ ],
+ "parameters": {
+ "Right": 0
+ },
+ "nullable": [
+ false
+ ]
+ },
+ "hash": "35324f9148e3e7ce2d2aa62d69378ce28a2398b408bbc99ea1299315904d6673"
+}
diff --git a/src/server/web/pages/graph.rs b/src/server/web/pages/graph.rs
index 2ee99e3..e52893f 100644
--- a/src/server/web/pages/graph.rs
+++ b/src/server/web/pages/graph.rs
@@ -20,6 +20,84 @@ use crate::{
somehow,
};
+use self::util::MetricFolder;
+
+#[derive(Template)]
+#[template(
+ ext = "html",
+ source = "
+{% match self %}
+ {% when MetricTree::File with { name, metric } %}
+
+ {% when MetricTree::Folder with { name, metric, children } %}
+ {% if let Some(metric) = metric %}
+
+ {% endif %}
+
+ {{ name }}/
+ {{ children|safe }}
+
+{% endmatch %}
+"
+)]
+enum MetricTree {
+ File {
+ name: String,
+ metric: String,
+ },
+ Folder {
+ name: String,
+ metric: Option,
+ children: MetricForest,
+ },
+}
+
+#[derive(Template)]
+#[template(
+ ext = "html",
+ source = "
+
+ {% for tree in trees %}
+ - {{ tree|safe }}
+ {% endfor %}
+
+"
+)]
+struct MetricForest {
+ trees: Vec,
+}
+
+impl MetricForest {
+ fn from_forest(children: HashMap) -> Self {
+ let mut children = children.into_iter().collect::>();
+ children.sort_unstable_by(|a, b| a.0.cmp(&b.0));
+
+ let mut trees = vec![];
+ for (name, mut folder) in children {
+ if let Some(file_metric) = folder.metric {
+ trees.push(MetricTree::File {
+ name: name.clone(),
+ metric: file_metric,
+ });
+ }
+
+ let is_folder = !folder.children.is_empty();
+ let folder_metric = folder.children.remove("").and_then(|f| f.metric);
+ if is_folder {
+ trees.push(MetricTree::Folder {
+ name,
+ metric: folder_metric,
+ children: Self::from_forest(folder.children),
+ })
+ }
+ }
+ Self { trees }
+ }
+}
+
// TODO Metric tree selector in template
#[derive(Template)]
#[template(path = "pages/graph.html")]
@@ -27,17 +105,31 @@ struct Page {
link_uplot_css: Link,
link_graph_js: Link,
base: Base,
+
+ metrics: MetricForest,
}
pub async fn get_graph(
_path: PathGraph,
State(config): State<&'static Config>,
+ State(db): State,
) -> somehow::Result {
+ let metrics =
+ sqlx::query_scalar!("SELECT DISTINCT metric FROM run_measurements ORDER BY metric ASC")
+ .fetch_all(&db)
+ .await?;
+
+ let metrics = MetricFolder::new(metrics);
+ assert!(metrics.metric.is_none());
+ let metrics = MetricForest::from_forest(metrics.children);
+
let base = Base::new(config, Tab::Graph);
Ok(Page {
link_uplot_css: base.link(UPLOT_CSS),
link_graph_js: base.link(GRAPH_JS),
base,
+
+ metrics,
})
}
diff --git a/src/server/web/pages/graph/util.rs b/src/server/web/pages/graph/util.rs
index 23ea854..3fb58dc 100644
--- a/src/server/web/pages/graph/util.rs
+++ b/src/server/web/pages/graph/util.rs
@@ -1,5 +1,29 @@
use std::collections::{HashMap, HashSet};
+#[derive(Default)]
+pub struct MetricFolder {
+ pub metric: Option,
+ pub children: HashMap,
+}
+
+impl MetricFolder {
+ fn insert(&mut self, metric: String) {
+ let mut current = self;
+ for segment in metric.split('/') {
+ current = current.children.entry(segment.to_string()).or_default();
+ }
+ current.metric = Some(metric);
+ }
+
+ pub fn new(metrics: Vec) -> Self {
+ let mut tree = Self::default();
+ for metric in metrics {
+ tree.insert(metric);
+ }
+ tree
+ }
+}
+
/// Sort commits topologically such that parents come before their children.
///
/// Assumes that `parent_child_pairs` contains no duplicates and is in the
diff --git a/templates/pages/graph.html b/templates/pages/graph.html
index ac2dde8..b1e68a3 100644
--- a/templates/pages/graph.html
+++ b/templates/pages/graph.html
@@ -7,6 +7,32 @@
{% endblock %}
+{# {% macro metric_tree(tree) %}
+{% match tree %}
+{% when File with { name, metric } %}
+
+{% when Folder with { name, metric, children } %}
+
+ {{ name }}/
+ {% call metric_forest(children) %}
+
+{% endmatch %}
+{% endmacro %}
+
+{% macro metric_forest(trees) %}
+
+ {% for tree in forest %}
+ {% call metric_tree(tree) %}
+ {% endfor %}
+
+{% endmacro %} #}
+
{% block body %}
+
Graph
+
+
+
+{{ metrics|safe }}
+
{% endblock %}