feat always smooth graph trends

- remove the redundant smoothing checkbox and client-side toggle state - request smooth=1 explicitly for every dashboard graph - retain smooth=0 as the external series API default - verify unsmoothed default output in the series tests

Commit
5ec97480f0b9913f486bc863e9d72843a9a55c19
Author
GPT-5 Codex high <codex@openai.com>
Author date
Committer
GPT-5 Codex high <codex@openai.com>
Committer date
Changed files
roles/dashboard/public/css/app.css
index 29abd776..a49abb3a 100644..100644
@@ -140,13 +140,11 @@
140 140
141 141 .toolbar .graph-control,
142 142 .toolbar .status-pill,
143 Removed: .toolbar .timeframe-control,
144 Removed: .toolbar .smoothing-control {
143 Added: .toolbar .timeframe-control {
145 144 min-height: var(--toolbar-item-height);
146 145 }
147 146
148 Removed: .toolbar .status-pill,
149 Removed: .toolbar .smoothing-control {
147 Added: .toolbar .status-pill {
150 148 align-items: center;
151 149 justify-content: center;
152 150 }
@@ -865,23 +863,6 @@
865 863 color: white;
866 864 }
867 865
868 Removed: .smoothing-control {
869 Removed: display: inline-flex;
870 Removed: align-items: center;
871 Removed: gap: 0.45rem;
872 Removed: min-height: 2.05rem;
873 Removed: color: var(--text);
874 Removed: cursor: pointer;
875 Removed: font-size: 0.88rem;
876 Removed: font-weight: 700;
877 Removed: }
878 Removed:
879 Removed: .smoothing-control input {
880 Removed: width: 1rem;
881 Removed: height: 1rem;
882 Removed: accent-color: var(--accent);
883 Removed: }
884 Removed:
885 866 .chart-wrap {
886 867 position: relative;
887 868 width: 100%;
@@ -1238,11 +1219,6 @@
1238 1219
1239 1220 .timeframe-option:nth-child(odd) .timeframe-button {
1240 1221 border-left: 0;
1241 Removed: }
1242 Removed:
1243 Removed: .smoothing-control {
1244 Removed: width: 100%;
1245 Removed: min-height: 2.75rem;
1246 1222 }
1247 1223
1248 1224 .section-heading {
roles/dashboard/public/js/dashboard.js
index 854ac97a..3699a281 100644..100644
@@ -65,7 +65,6 @@
65 65 const TRANSPARENT_CHART_COLOR = "rgba(39, 103, 73, 0)";
66 66 let activeTimeframe = DEFAULT_TIMEFRAME;
67 67 let expandedTimeframe = null;
68 Removed: let smoothingEnabled = true;
69 68 const timeframeRanges = Object.fromEntries(
70 69 Object.keys(TIMEFRAMES).map(timeframe => [timeframe, 1])
71 70 );
@@ -122,10 +121,6 @@
122 121 return Array.from(document.querySelectorAll("[data-status-page-item]"));
123 122 }
124 123
125 Removed: function smoothingToggles() {
126 Removed: return Array.from(document.querySelectorAll("[data-smoothing-toggle]"));
127 Removed: }
128 Removed:
129 124 function rawDownloadLinks() {
130 125 return Array.from(document.querySelectorAll("[data-raw-download]"));
131 126 }
@@ -674,7 +669,7 @@
674 669 const seriesParams = new URLSearchParams({
675 670 timeframe: selectedTimeframe(),
676 671 range: String(selectedTimeframeRange()),
677 Removed: smooth: smoothingEnabled ? "1" : "0"
672 Added: smooth: "1"
678 673 });
679 674 const readingsParams = new URLSearchParams({
680 675 limit: "10"
@@ -706,7 +701,7 @@
706 701 probe,
707 702 [...series.lower, ...series.upper, ...series.trend]
708 703 );
709 Removed: const trendLabel = `${probe} ${unit ? `(${unit})` : ""}${smoothingEnabled ? " trend" : " median"}`;
704 Added: const trendLabel = `${probe} ${unit ? `(${unit})` : ""} trend`;
710 705
711 706 if (!charts.has(probe)) {
712 707 const ctx = chartElement(probe);
@@ -892,16 +887,6 @@
892 887 displayedProbes().forEach(loadProbe);
893 888 }
894 889
895 Removed: function setSmoothing(enabled) {
896 Removed: smoothingEnabled = enabled;
897 Removed:
898 Removed: smoothingToggles().forEach(toggle => {
899 Removed: toggle.checked = smoothingEnabled;
900 Removed: });
901 Removed:
902 Removed: displayedProbes().forEach(loadProbe);
903 Removed: }
904 Removed:
905 890 function probeFromHash() {
906 891 const match = window.location.hash.match(/^#probe-([a-z]+)$/);
907 892 const probe = match ? match[1] : null;
@@ -936,12 +921,6 @@
936 921 button.addEventListener("click", () => {
937 922 const adjustment = button.dataset.timeframeAdjustment === "increase" ? 1 : -1;
938 923 adjustTimeframeRange(button.dataset.timeframe, adjustment);
939 Removed: });
940 Removed: });
941 Removed:
942 Removed: smoothingToggles().forEach(toggle => {
943 Removed: toggle.addEventListener("change", () => {
944 Removed: setSmoothing(toggle.checked);
945 924 });
946 925 });
947 926
roles/dashboard/t/01-graph-page.t
index 890dccfa..d5a56f18 100644..100644
@@ -26,7 +26,6 @@
26 26 'button[data-graph-controls-toggle][aria-expanded="false"][aria-controls="graph-controls-panel"]',
27 27 'Graph controls'
28 28 )
29 Removed: ->element_exists('input[data-smoothing-toggle][checked]')
30 29 ->text_is( 'a[data-raw-download][data-probe="ph"]', 'Download raw data' )
31 30 ->element_exists('tbody[data-reading-messages="ph"]')
32 31 ->element_exists_not('section#probe-do[data-panel="do"]');
@@ -45,8 +44,7 @@
45 44 ->text_is( 'nav.breadcrumbs a[href="/"]', 'Home' )
46 45 ->text_is( 'nav.breadcrumbs [aria-current="page"]', 'Probes' )
47 46 ->element_exists('div.probes-grid')
48 Removed: ->element_exists('div.toolbar-items div.graph-control')
49 Removed: ->element_exists('input[data-smoothing-toggle][checked]');
47 Added: ->element_exists('div.toolbar-items div.graph-control');
50 48
51 49 for my $probe (qw(ph do orp ec)) {
52 50 $t->element_exists(qq{div.probes-grid h1 a[href="/probes/$probe"]});
roles/dashboard/t/04-readings-series.t
index effe3dfe..e519fd99 100644..100644
@@ -19,6 +19,7 @@
19 19 ->status_is(200)
20 20 ->json_is( '/probe' => 'ec' )
21 21 ->json_is( '/timeframe' => 'hour' )
22 Added: ->json_is( '/smooth' => 0 )
22 23 ->json_is( '/band/lower_percentile' => 10 )
23 24 ->json_is( '/band/upper_percentile' => 90 )
24 25 ->json_is( '/gap_seconds' => 30 )
@@ -47,7 +48,7 @@
47 48 ->json_hasnt('/readings/168');
48 49 assert_series_reading( $t, 1050, 1000, 1100, 2 );
49 50
50 Removed: $t->get_ok('/api/readings/orp/series?timeframe=hour&smooth=0')
51 Added: $t->get_ok('/api/readings/orp/series?timeframe=hour')
51 52 ->status_is(200)
52 53 ->json_is( '/smooth' => 0 )
53 54 ->json_is( '/readings/52/value' => 70 )
roles/dashboard/templates/dashboard/graph-control.html.ep
index 75c8d0d2..da8a5e56 100644..100644
@@ -32,10 +32,6 @@
32 32 </div>
33 33 % }
34 34 </div>
35 Removed: <label class="smoothing-control">
36 Removed: <input type="checkbox" data-smoothing-toggle checked>
37 Removed: <span>Smoothed</span>
38 Removed: </label>
39 35 </div>
40 36 </div>
41 37 </div>