From 13c80e555e124e501b75011dd118ca385a82ade1 Mon Sep 17 00:00:00 2001
From: Udo Eisenbarth <u.eisenbarth@gsi.de>
Date: Mon, 28 Oct 2024 08:50:07 +0000
Subject: [PATCH] * Add field 'show_item' to NodeReport to control if item to
 be displayed in HTML.

* feat: :sparkles: Make sections in HTML Reports collapsable.
---
 opossum/src/analyzers/ghostfocus.rs  |  3 +-
 opossum/src/html/html_report.html    | 85 +++++++++++++++-------------
 opossum/src/html/node_report.html    | 34 +++++------
 opossum/src/nodes/node_group/mod.rs  |  8 ++-
 opossum/src/properties/proptype.rs   |  1 +
 opossum/src/reporting/html_report.rs |  2 +
 opossum/src/reporting/node_report.rs | 10 ++++
 7 files changed, 85 insertions(+), 58 deletions(-)

diff --git a/opossum/src/analyzers/ghostfocus.rs b/opossum/src/analyzers/ghostfocus.rs
index 59485bdc..4ee2df3e 100644
--- a/opossum/src/analyzers/ghostfocus.rs
+++ b/opossum/src/analyzers/ghostfocus.rs
@@ -115,8 +115,9 @@ impl Analyzer for GhostFocusAnalyzer {
         let proptype = Proptype::from(ghost_focus_history);
         props.create("propagation", "ray propagation", None, proptype)?;
 
-        let node_report =
+        let mut node_report =
             NodeReport::new("ray propagation", "Global ray propagation", "global", props);
+        node_report.set_show_item(true);
         analysis_report.add_node_report(node_report);
         for node in scenery.graph().nodes() {
             let node_name = &node.optical_ref.borrow().name();
diff --git a/opossum/src/html/html_report.html b/opossum/src/html/html_report.html
index fd33f141..72423c8b 100644
--- a/opossum/src/html/html_report.html
+++ b/opossum/src/html/html_report.html
@@ -1,50 +1,57 @@
 <!DOCTYPE html>
 <html class="h-100" lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta name="description" content="OPOSSUM Analysis Report" />
-    <meta name="keywords" content="OPOSSUM,Laser,Simulation,Optics" />
-    <meta name="author" content="Udo Eisenbarth" />
-    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
-    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
-    <title>OPOSSUM Analysis Report</title>
-  </head>
-  <body class="d-flex flex-column h-100">
-    <main class="flex-shrink-0" role="main">
-      <div class="container justify-content-center">
-        <div class="row">
-          <div class="col">
-            <div class="mx-auto p-2" style="width: 150px;">
-              <img src="Logo_square.svg" class="img-fluid" alt="OPOSSUM"/>
-            </div>
+
+<head>
+  <meta charset="UTF-8" />
+  <meta name="description" content="OPOSSUM Analysis Report" />
+  <meta name="keywords" content="OPOSSUM,Laser,Simulation,Optics" />
+  <meta name="author" content="Udo Eisenbarth" />
+  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
+  <title>OPOSSUM Analysis Report</title>
+</head>
+
+<body class="d-flex flex-column">
+  <main class="flex-shrink-0" role="main">
+    <div class="container justify-content-center">
+      <div class="row">
+        <div class="col">
+          <div class="mx-auto p-2" style="width: 150px;">
+            <img src="Logo_square.svg" class="img-fluid" alt="OPOSSUM" />
           </div>
         </div>
-        <div class="row">
-          <div class="col">
-              <h1 class="text-center">{analysis_type} Report</h1>
-          </div>
+      </div>
+      <div class="row">
+        <div class="col">
+          <h1 class="text-center">{analysis_type} Report</h1>
         </div>
-        <div class="row">
-          <div class="col-md-6 text-start">
-            <span class="small">OPOSSUM version: {opossum_version}</span>
-          </div>
-          <div class="col-md-6 text-end">
-            <span class="small">Analysis date: {analysis_timestamp}</span>
-          </div>
+      </div>
+      <div class="row">
+        <div class="col-md-6 text-start">
+          <span class="small">OPOSSUM version: {opossum_version}</span>
+        </div>
+        <div class="col-md-6 text-end">
+          <span class="small">Analysis date: {analysis_timestamp}</span>
         </div>
-        <hr/>
-        <div class="row">
-          <div class="col">
-              <h3>{description}</h3>
-              <div class="text-center">
-                <img src="scenery.svg" class="img-fluid" style="max-height: 600pt;" alt="Optical scene diagram"/>
-              </div>
+      </div>
+      <hr />
+      <div class="row">
+        <div class="col">
+          <h3>{description}</h3>
+          <div class="text-center">
+            <img src="scenery.svg" class="img-fluid" style="max-height: 600pt; break-after:all;"
+              alt="Optical scene diagram" />
           </div>
         </div>
+      </div>
+      <div class="accordion" id="nodeAccordion">
         {{ for node_report in node_reports}}{{ call node_report with node_report }}{{ endfor }}
       </div>
-    </main>
-    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
-  </body>
+    </div>
+  </main>
+  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
+
+</body>
+
 </html>
\ No newline at end of file
diff --git a/opossum/src/html/node_report.html b/opossum/src/html/node_report.html
index ca40378d..d35e64cc 100644
--- a/opossum/src/html/node_report.html
+++ b/opossum/src/html/node_report.html
@@ -1,19 +1,19 @@
-<div class="row mb-1">
-  <div class="col">
-    <div class="card">
-      <div class="card-header">
-        <span class="h5">{node_name}</span> <small class="muted">{node_type}</small>
-      </div>
-      <div class="card-body">
-        <table class="table table-sm table-bordered">
-          <tbody>
-            {{for property in props}}<tr>
-              <th class="text-end" scope="row" style="width:20ch"><abbr title="{property.description}">{property.name}</abbr>:</th>
-              <td style="width:auto">{property.prop_value | unescaped}</td>
-            </tr>{{ endfor }}
-          </tbody>
-        </table>
-      </div>
+<div class="accordion-item">
+  <h5 class="accordion-header">
+    <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#{uuid}">
+      <span class="h5 me-2">{node_name}</span><small class="muted">{node_type}</small>
+    </button>
+  </h5>
+  <div id="{uuid}" class="accordion-collapse collapse {{ if show_item }}show{{ endif }}">
+    <div class="accordion-body">
+      <table class="table table-sm table-bordered">
+        <tbody>
+          {{for property in props}}<tr>
+            <th class="text-end" scope="row" style="width:20ch"><abbr title="{property.description}">{property.name}</abbr>:</th>
+            <td style="width:auto">{property.prop_value | unescaped}</td>
+          </tr>{{ endfor }}
+        </tbody>
+      </table>
     </div>
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/opossum/src/nodes/node_group/mod.rs b/opossum/src/nodes/node_group/mod.rs
index 7432ac8b..e159827a 100644
--- a/opossum/src/nodes/node_group/mod.rs
+++ b/opossum/src/nodes/node_group/mod.rs
@@ -21,6 +21,7 @@ use crate::{
     SceneryResources,
 };
 use chrono::Local;
+use num::Zero;
 pub use optic_graph::OpticGraph;
 use petgraph::prelude::NodeIndex;
 use serde::{Deserialize, Serialize};
@@ -352,10 +353,15 @@ impl NodeGroup {
     pub fn toplevel_report(&self) -> OpmResult<AnalysisReport> {
         let mut analysis_report = AnalysisReport::new(get_version(), Local::now());
         analysis_report.add_scenery(self);
+        let mut section_number: usize = 0;
         for node in self.graph.nodes() {
             let uuid = node.uuid().as_simple().to_string();
-            if let Some(node_report) = node.optical_ref.borrow().node_report(&uuid) {
+            if let Some(mut node_report) = node.optical_ref.borrow().node_report(&uuid) {
+                if section_number.is_zero() {
+                    node_report.set_show_item(true);
+                }
                 analysis_report.add_node_report(node_report);
+                section_number += 1;
             }
         }
         Ok(analysis_report)
diff --git a/opossum/src/properties/proptype.rs b/opossum/src/properties/proptype.rs
index d8e7efd6..911e7427 100644
--- a/opossum/src/properties/proptype.rs
+++ b/opossum/src/properties/proptype.rs
@@ -155,6 +155,7 @@ impl Proptype {
                         report.uuid()
                     )),
                     uuid: report.uuid().to_string(),
+                    show_item: report.show_item(),
                 };
                 tt.render("group", &html_node_report)
             }
diff --git a/opossum/src/reporting/html_report.rs b/opossum/src/reporting/html_report.rs
index 0e87d48f..c91082f9 100644
--- a/opossum/src/reporting/html_report.rs
+++ b/opossum/src/reporting/html_report.rs
@@ -67,6 +67,8 @@ pub struct HtmlNodeReport {
     pub props: Vec<HtmlProperty>,
     /// uuid of the node (needed for constructing filenames)
     pub uuid: String,
+    /// show or hide item in report by default
+    pub show_item: bool,
 }
 
 #[derive(Serialize)]
diff --git a/opossum/src/reporting/node_report.rs b/opossum/src/reporting/node_report.rs
index 73f1aa34..56b42f09 100644
--- a/opossum/src/reporting/node_report.rs
+++ b/opossum/src/reporting/node_report.rs
@@ -16,6 +16,7 @@ pub struct NodeReport {
     name: String,
     uuid: String,
     properties: Properties,
+    show_item: bool,
 }
 impl NodeReport {
     /// Creates a new [`NodeReport`].
@@ -26,6 +27,7 @@ impl NodeReport {
             name: name.to_owned(),
             uuid: uuid.to_string(),
             properties,
+            show_item: false,
         }
     }
     /// Returns a reference to the node type of this [`NodeReport`].
@@ -53,6 +55,7 @@ impl NodeReport {
                 .properties
                 .html_props(&format!("{id}_{}_{}", self.name, self.uuid)),
             uuid: self.uuid.clone(),
+            show_item: self.show_item,
         }
     }
     /// Returns a reference to the uuid of this [`NodeReport`].
@@ -69,6 +72,13 @@ impl NodeReport {
         self.properties
             .export_data(report_path, &format!("{id}_{}_{}", &self.name, &self.uuid))
     }
+    #[must_use]
+    pub const fn show_item(&self) -> bool {
+        self.show_item
+    }
+    pub fn set_show_item(&mut self, show_item: bool) {
+        self.show_item = show_item;
+    }
 }
 
 impl From<NodeReport> for Proptype {
-- 
GitLab