refactor flatten insights into a single list of charts

Remove the 'At a Glance' / 'Explore' section split and the nav pills with scroll spy. All charts are now presented as a flat vertical list. Grouping will be rationalised later.

Commit
fe5aa2b7ecf02ad1ee66f72052cb9b94833cd5e1
Author
GPT-5 medium <codex@openai.com>
Author date
Committer
GPT-5 medium <codex@openai.com>
Committer date
Changed files
roles/dashboard/public/js/dashboard/insights.js
index c2444317..75e6791a 100644..100644
@@ -429,9 +429,6 @@
429 429 // Initial load
430 430 loadAll();
431 431
432 Removed: // Scroll spy
433 Removed: initScrollSpy();
434 Removed:
435 432 return {
436 433 reload() {
437 434 loadAll();
@@ -439,25 +436,3 @@
439 436 };
440 437 }
441 438
442 Removed: // ──────────────────────────────────────────────────────────────────
443 Removed: // Scroll spy: highlight active nav pill based on visible section
444 Removed: // ──────────────────────────────────────────────────────────────────
445 Removed: function initScrollSpy() {
446 Removed: const navLinks = document.querySelectorAll(".insights-nav a.nav-link");
447 Removed: const sections = document.querySelectorAll(".insight-theme[id]");
448 Removed:
449 Removed: if (!navLinks.length || !sections.length) return;
450 Removed:
451 Removed: const observer = new IntersectionObserver(entries => {
452 Removed: for (const entry of entries) {
453 Removed: if (entry.isIntersecting) {
454 Removed: const id = entry.target.id;
455 Removed: navLinks.forEach(link => {
456 Removed: link.classList.toggle("active", link.getAttribute("href") === `#${id}`);
457 Removed: });
458 Removed: }
459 Removed: }
460 Removed: }, { rootMargin: "-20% 0px -60% 0px" });
461 Removed:
462 Removed: sections.forEach(section => observer.observe(section));
463 Removed: }
roles/dashboard/t/08-insights.t
index 64cad1bd..8ed12731 100644..100644
@@ -19,16 +19,6 @@
19 19 ->element_exists('[data-default-timeframe="day"]');
20 20 };
21 21
22 Removed: subtest 'insights page has section anchors and nav' => sub {
23 Removed: $t->get_ok('/insights')
24 Removed: ->status_is(200)
25 Removed: ->element_exists('nav.insights-nav')
26 Removed: ->element_exists('a.nav-link[href="#at-a-glance"]')
27 Removed: ->element_exists('a.nav-link[href="#explore"]')
28 Removed: ->element_exists('section#at-a-glance')
29 Removed: ->element_exists('section#explore');
30 Removed: };
31 Removed:
32 22 subtest 'insights page has all chart canvases' => sub {
33 23 $t->get_ok('/insights')
34 24 ->status_is(200)
roles/dashboard/templates/dashboard/insights.html.ep
index b43c15db..147aeff7 100644..100644
@@ -11,116 +11,89 @@
11 11 %= include 'dashboard/graph-control', aria_label => 'Insights timeframe', default_timeframe => 'day'
12 12 </div>
13 13
14 Removed: <nav class="insights-nav mb-4" aria-label="Insight sections">
15 Removed: <ul class="nav nav-pills nav-fill flex-nowrap overflow-x-auto">
16 Removed: <li class="nav-item">
17 Removed: <a class="nav-link" href="#at-a-glance">At a Glance</a>
18 Removed: </li>
19 Removed: <li class="nav-item">
20 Removed: <a class="nav-link" href="#explore">Explore</a>
21 Removed: </li>
22 Removed: </ul>
23 Removed: </nav>
24 Removed:
25 Removed: <!-- ════════════════════════════════════════════════════════════════
26 Removed: AT A GLANCE
27 Removed: ════════════════════════════════════════════════════════════════ -->
28 Removed: <section id="at-a-glance" class="insight-theme mb-5">
29 Removed: <h2 class="h5 fw-bold mb-3 text-body-secondary">At a Glance</h2>
30 Removed:
31 Removed: <div class="row g-3">
32 Removed: <div class="col-12" id="stability">
33 Removed: <div class="card">
34 Removed: <div class="card-header">
35 Removed: <h3 class="h6 mb-0">System Stability</h3>
36 Removed: <p class="text-body-secondary small mb-0 mt-1">
37 Removed: A <strong>lower score means more stable</strong>.
38 Removed: This index is the rolling standard deviation (σ) of all probe values
39 Removed: over a 6-hour window, normalised to each probe's optimal range.
40 Removed: Spikes indicate rapid or large deviations from normal operating conditions.
41 Removed: </p>
14 Added: <div class="row g-3">
15 Added: <div class="col-12" id="stability">
16 Added: <div class="card">
17 Added: <div class="card-header">
18 Added: <h2 class="h6 mb-0">System Stability</h2>
19 Added: <p class="text-body-secondary small mb-0 mt-1">
20 Added: A <strong>lower score means more stable</strong>.
21 Added: This index is the rolling standard deviation (σ) of all probe values
22 Added: over a 6-hour window, normalised to each probe's optimal range.
23 Added: Spikes indicate rapid or large deviations from normal operating conditions.
24 Added: </p>
25 Added: </div>
26 Added: <div class="card-body">
27 Added: <div class="chart-wrap">
28 Added: <canvas id="chart-stability" role="img" aria-label="System stability score — lower is better"></canvas>
42 29 </div>
43 Removed: <div class="card-body">
44 Removed: <div class="chart-wrap">
45 Removed: <canvas id="chart-stability" role="img" aria-label="System stability score — lower is better"></canvas>
46 Removed: </div>
47 Removed: </div>
48 30 </div>
49 31 </div>
32 Added: </div>
50 33
51 Removed: <div class="col-12" id="rate-of-change">
52 Removed: <div class="card">
53 Removed: <div class="card-header">
54 Removed: <h3 class="h6 mb-0">Rate of Change</h3>
55 Removed: <p class="text-body-secondary small mb-0 mt-1">
56 Removed: Normalised rate of change per probe (% of optimal range per hour).
57 Removed: Values near zero mean the parameter is steady.
58 Removed: </p>
34 Added: <div class="col-12" id="rate-of-change">
35 Added: <div class="card">
36 Added: <div class="card-header">
37 Added: <h2 class="h6 mb-0">Rate of Change</h2>
38 Added: <p class="text-body-secondary small mb-0 mt-1">
39 Added: Normalised rate of change per probe (% of optimal range per hour).
40 Added: Values near zero mean the parameter is steady.
41 Added: </p>
42 Added: </div>
43 Added: <div class="card-body">
44 Added: <div class="chart-wrap">
45 Added: <canvas id="chart-derivatives" role="img" aria-label="Normalised rate of change per probe"></canvas>
59 46 </div>
60 Removed: <div class="card-body">
61 Removed: <div class="chart-wrap">
62 Removed: <canvas id="chart-derivatives" role="img" aria-label="Normalised rate of change per probe"></canvas>
63 Removed: </div>
64 Removed: </div>
65 47 </div>
66 48 </div>
49 Added: </div>
67 50
68 Removed: <div class="col-12" id="diurnal">
69 Removed: <div class="card">
70 Removed: <div class="card-header">
71 Removed: <h3 class="h6 mb-0">DO Diurnal Pattern</h3>
72 Removed: <p class="text-body-secondary small mb-0 mt-1">
73 Removed: Day/night DO cycle &mdash; each line is one day, bold is the average
74 Removed: </p>
51 Added: <div class="col-12" id="diurnal">
52 Added: <div class="card">
53 Added: <div class="card-header">
54 Added: <h2 class="h6 mb-0">DO Diurnal Pattern</h2>
55 Added: <p class="text-body-secondary small mb-0 mt-1">
56 Added: Day/night DO cycle &mdash; each line is one day, bold is the average
57 Added: </p>
58 Added: </div>
59 Added: <div class="card-body">
60 Added: <div class="chart-wrap">
61 Added: <canvas id="chart-diurnal" role="img" aria-label="Dissolved oxygen diurnal overlay"></canvas>
75 62 </div>
76 Removed: <div class="card-body">
77 Removed: <div class="chart-wrap">
78 Removed: <canvas id="chart-diurnal" role="img" aria-label="Dissolved oxygen diurnal overlay"></canvas>
79 Removed: </div>
80 Removed: </div>
81 63 </div>
82 64 </div>
83 65 </div>
84 Removed: </section>
85 66
86 Removed: <!-- ════════════════════════════════════════════════════════════════
87 Removed: EXPLORE — Same timeframe as above (page-level controls)
88 Removed: ════════════════════════════════════════════════════════════════ -->
89 Removed: <section id="explore" class="insight-theme mb-5">
90 Removed: <h2 class="h5 fw-bold mb-3 text-body-secondary">Explore</h2>
91 Removed:
92 Removed: <div class="row g-3">
93 Removed: <div class="col-12" id="do-orp-overlay">
94 Removed: <div class="card">
95 Removed: <div class="card-header">
96 Removed: <h3 class="h6 mb-0">DO &amp; ORP Over Time</h3>
97 Removed: <p class="text-body-secondary small mb-0 mt-1">
98 Removed: Dual-axis overlay &mdash; correlated drops indicate oxygen-driven redox shifts
99 Removed: </p>
67 Added: <div class="col-12" id="do-orp-overlay">
68 Added: <div class="card">
69 Added: <div class="card-header">
70 Added: <h2 class="h6 mb-0">DO &amp; ORP Over Time</h2>
71 Added: <p class="text-body-secondary small mb-0 mt-1">
72 Added: Dual-axis overlay &mdash; correlated drops indicate oxygen-driven redox shifts
73 Added: </p>
74 Added: </div>
75 Added: <div class="card-body">
76 Added: <div class="chart-wrap">
77 Added: <canvas id="chart-overlay-do-orp" role="img" aria-label="DO and ORP overlay chart"></canvas>
100 78 </div>
101 Removed: <div class="card-body">
102 Removed: <div class="chart-wrap">
103 Removed: <canvas id="chart-overlay-do-orp" role="img" aria-label="DO and ORP overlay chart"></canvas>
104 Removed: </div>
105 Removed: </div>
106 79 </div>
107 80 </div>
81 Added: </div>
108 82
109 Removed: <div class="col-12" id="ph-do-lag">
110 Removed: <div class="card">
111 Removed: <div class="card-header">
112 Removed: <h3 class="h6 mb-0">pH &#8596; DO Relationship</h3>
113 Removed: <p class="text-body-secondary small mb-0 mt-1">
114 Removed: Nitrification link &mdash; DO drops often precede pH drops
115 Removed: </p>
83 Added: <div class="col-12" id="ph-do-lag">
84 Added: <div class="card">
85 Added: <div class="card-header">
86 Added: <h2 class="h6 mb-0">pH &#8596; DO Relationship</h2>
87 Added: <p class="text-body-secondary small mb-0 mt-1">
88 Added: Nitrification link &mdash; DO drops often precede pH drops
89 Added: </p>
90 Added: </div>
91 Added: <div class="card-body">
92 Added: <div class="chart-wrap">
93 Added: <canvas id="chart-ph-do-lag" role="img" aria-label="pH and DO relationship overlay"></canvas>
116 94 </div>
117 Removed: <div class="card-body">
118 Removed: <div class="chart-wrap">
119 Removed: <canvas id="chart-ph-do-lag" role="img" aria-label="pH and DO relationship overlay"></canvas>
120 Removed: </div>
121 Removed: </div>
122 95 </div>
123 96 </div>
124 97 </div>
125 Removed: </section>
98 Added: </div>
126 99 </section>