From 81e7e3c9af97dace90761f0383a1f124374d1dfb Mon Sep 17 00:00:00 2001 From: Emiliano Frascaro Date: Tue, 8 Sep 2026 22:07:07 +0200 Subject: [PATCH] Semplifica il grafico analytics: solo pageview e toggle nascondi. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chiarisce che il totale è su tutte le pagine (filtri Da/A/Device), distinto dal dettaglio per path. Co-authored-by: Cursor --- .../app/views/admin/analytics/index.html.erb | 48 +++++++------- backend/app/views/layouts/admin.html.erb | 2 +- backend/config/locales/admin.de.yml | 10 ++- backend/config/locales/admin.en.yml | 10 ++- backend/config/locales/admin.es.yml | 10 ++- backend/config/locales/admin.fr.yml | 10 ++- backend/config/locales/admin.it.yml | 10 ++- backend/public/admin-analytics.js | 62 +++++++++++-------- backend/public/admin.css | 21 +++++++ backend/spec/requests/admin/analytics_spec.rb | 21 ++++++- 10 files changed, 143 insertions(+), 61 deletions(-) diff --git a/backend/app/views/admin/analytics/index.html.erb b/backend/app/views/admin/analytics/index.html.erb index c415afd..5aa485c 100644 --- a/backend/app/views/admin/analytics/index.html.erb +++ b/backend/app/views/admin/analytics/index.html.erb @@ -58,42 +58,48 @@ <% end %> -<% if @trend.any? && (@trend_totals[:pageviews].positive? || @trend_totals[:clicks].positive? || @trend_totals[:moves].positive?) %> -
-

<%= t("admin.analytics.index.trend_title") %>

-

<%= t("admin.analytics.index.trend_lead") %>

-
-
-
<%= t("admin.analytics.index.table.pageviews") %>
-
<%= @trend_totals[:pageviews] %>
-
-
-
<%= t("admin.analytics.index.table.clicks") %>
-
<%= @trend_totals[:clicks] %>
-
-
-
<%= t("admin.analytics.index.table.moves") %>
-
<%= @trend_totals[:moves] %>
+<% if @trend.any? && @trend_totals[:pageviews].positive? %> +
+
+
+

<%= t("admin.analytics.index.trend_title") %>

+

<%= t("admin.analytics.index.trend_lead") %>

+
-
- "> +
+
+
+
<%= t("admin.analytics.index.trend_total_label") %>
+
<%= @trend_totals[:pageviews] %>
+
<%= t("admin.analytics.index.trend_total_hint", from: l(@filters[:from]), to: l(@filters[:to])) %>
+
+
+
+ "> +
- + <% end %>
<% if @pages.any? %> +

<%= t("admin.analytics.index.pages_title") %>

+

<%= t("admin.analytics.index.pages_lead") %>

diff --git a/backend/app/views/layouts/admin.html.erb b/backend/app/views/layouts/admin.html.erb index 9b34054..0d15280 100644 --- a/backend/app/views/layouts/admin.html.erb +++ b/backend/app/views/layouts/admin.html.erb @@ -5,7 +5,7 @@ <%= csrf_meta_tags %> - + <%= yield :head %> <% if content_for?(:replay_archive_styles) %> diff --git a/backend/config/locales/admin.de.yml b/backend/config/locales/admin.de.yml index eae76cd..568f35b 100644 --- a/backend/config/locales/admin.de.yml +++ b/backend/config/locales/admin.de.yml @@ -427,8 +427,14 @@ de: lead: Aggregierte First-Party-Heatmaps (Bewegung/Klick) und Scrolltiefe, nur mit Statistik-Einwilligung. Keine personenbezogenen Daten. none: Keine Daten im gewählten Zeitraum. heatmap: Heatmap - trend_title: Verlauf über die Zeit - trend_lead: Tägliche Pageviews, Klicks und Bewegungen im gefilterten Zeitraum. + trend_title: Pageview-Verlauf + trend_lead: Gesamte Pageviews aller Seiten, Tag für Tag. Dieselben Filter Von / Bis / Gerät. Nicht mit einer Tabellenzeile vergleichbar (die nach Pfad trennt). + trend_total_label: Pageviews gesamt (alle Seiten) + trend_total_hint: "%{from} → %{to}" + hide_chart: Diagramm ausblenden + show_chart: Diagramm anzeigen + pages_title: Aufschlüsselung nach Seite + pages_lead: Pageviews und Engagement im gefilterten Zeitraum, nach Pfad. Die Summe der Pageview-Zeilen entspricht dem Diagramm-Total. table: path: Seite pageviews: Pageviews diff --git a/backend/config/locales/admin.en.yml b/backend/config/locales/admin.en.yml index 7fc5f49..937d01f 100644 --- a/backend/config/locales/admin.en.yml +++ b/backend/config/locales/admin.en.yml @@ -427,8 +427,14 @@ en: lead: Aggregated first-party move/click heatmaps and scroll depth, only with analytics consent. No personal data. none: No data in the selected period. heatmap: Heatmap - trend_title: Trend over time - trend_lead: Daily pageviews, clicks and moves for the filtered period. + trend_title: Pageview trend + trend_lead: Total pageviews across all pages, day by day. Uses the same From / To / Device filters. Not comparable to a single table row (which splits by path). + trend_total_label: Total pageviews (all pages) + trend_total_hint: "%{from} → %{to}" + hide_chart: Hide chart + show_chart: Show chart + pages_title: Breakdown by page + pages_lead: Pageviews and engagement for the filtered period, split by path. The sum of pageview rows matches the chart total. table: path: Page pageviews: Pageviews diff --git a/backend/config/locales/admin.es.yml b/backend/config/locales/admin.es.yml index 4870269..647d2b7 100644 --- a/backend/config/locales/admin.es.yml +++ b/backend/config/locales/admin.es.yml @@ -427,8 +427,14 @@ es: lead: Heatmaps de movimientos/clics y scroll agregados (first-party), solo con consentimiento estadístico. Sin datos personales. none: No hay datos en el periodo seleccionado. heatmap: Heatmap - trend_title: Evolución en el tiempo - trend_lead: Pageviews, clics y movimientos día a día en el periodo filtrado. + trend_title: Evolución de pageviews + trend_lead: Total de pageviews de todas las páginas, día a día. Usa los mismos filtros Desde / Hasta / Device. No es comparable con una fila de la tabla (que parte por path). + trend_total_label: Pageviews totales (todas las páginas) + trend_total_hint: "%{from} → %{to}" + hide_chart: Ocultar gráfico + show_chart: Mostrar gráfico + pages_title: Detalle por página + pages_lead: Pageviews y engagement en el periodo filtrado, por path. La suma de las filas coincide con el total del gráfico. table: path: Página pageviews: Pageviews diff --git a/backend/config/locales/admin.fr.yml b/backend/config/locales/admin.fr.yml index 5e844c5..4e37912 100644 --- a/backend/config/locales/admin.fr.yml +++ b/backend/config/locales/admin.fr.yml @@ -427,8 +427,14 @@ fr: lead: Heatmaps mouvements/clics et scroll agrégés (first-party), uniquement avec consentement statistiques. Aucune donnée personnelle. none: Aucune donnée sur la période sélectionnée. heatmap: Heatmap - trend_title: Évolution dans le temps - trend_lead: Pages vues, clics et mouvements par jour sur la période filtrée. + trend_title: Évolution des pages vues + trend_lead: Total des pages vues sur toutes les pages, jour par jour. Mêmes filtres De / À / Appareil. Non comparable à une ligne du tableau (découpée par chemin). + trend_total_label: Pages vues totales (toutes les pages) + trend_total_hint: "%{from} → %{to}" + hide_chart: Masquer le graphique + show_chart: Afficher le graphique + pages_title: Détail par page + pages_lead: Pages vues et engagement sur la période filtrée, par chemin. La somme des lignes égale le total du graphique. table: path: Page pageviews: Pages vues diff --git a/backend/config/locales/admin.it.yml b/backend/config/locales/admin.it.yml index 17f84c5..5bde8bd 100644 --- a/backend/config/locales/admin.it.yml +++ b/backend/config/locales/admin.it.yml @@ -448,8 +448,14 @@ it: lead: Heatmap movimenti/click e scroll aggregati (first-party), solo con consenso statistico. Nessun dato personale. none: Nessun dato nel periodo selezionato. heatmap: Heatmap - trend_title: Andamento nel tempo - trend_lead: Pageview, click e movimenti giorno per giorno nel periodo filtrato. + trend_title: Andamento pageview + trend_lead: Totale pageview di tutte le pagine, giorno per giorno. Usa gli stessi filtri Da / A / Device. Non è confrontabile con una singola riga della tabella (che spezza per path). + trend_total_label: Pageview totali (tutte le pagine) + trend_total_hint: "%{from} → %{to}" + hide_chart: Nascondi grafico + show_chart: Mostra grafico + pages_title: Dettaglio per pagina + pages_lead: Pageview e engagement nel periodo filtrato, spezzati per path. La somma delle pageview delle righe coincide col totale del grafico. table: path: Pagina pageviews: Pageview diff --git a/backend/public/admin-analytics.js b/backend/public/admin-analytics.js index 299d139..7e1f4bc 100644 --- a/backend/public/admin-analytics.js +++ b/backend/public/admin-analytics.js @@ -1,7 +1,40 @@ (function () { + var STORAGE_KEY = "mltv_admin_analytics_chart_hidden"; var trend = window.adminAnalyticsTrend || []; var i18n = window.adminAnalyticsI18n || {}; + var panel = document.getElementById("admin-analytics-trend"); var canvas = document.getElementById("chart-analytics-trend"); + var toggle = document.getElementById("admin-analytics-trend-toggle"); + var body = document.getElementById("admin-analytics-trend-body"); + + function setHidden(hidden) { + if (!panel || !body || !toggle) return; + body.hidden = hidden; + panel.classList.toggle("is-collapsed", hidden); + toggle.setAttribute("aria-expanded", hidden ? "false" : "true"); + toggle.textContent = hidden + ? (i18n.showChart || "Mostra grafico") + : (i18n.hideChart || "Nascondi grafico"); + try { + localStorage.setItem(STORAGE_KEY, hidden ? "1" : "0"); + } catch (e) { /* ignore */ } + } + + function initiallyHidden() { + try { + return localStorage.getItem(STORAGE_KEY) === "1"; + } catch (e) { + return false; + } + } + + if (toggle && body) { + setHidden(initiallyHidden()); + toggle.addEventListener("click", function () { + setHidden(!body.hidden); + }); + } + if (!canvas || !trend.length || typeof Chart === "undefined") return; function dayLabel(dayStr) { @@ -11,14 +44,10 @@ return d.toLocaleDateString([], { day: "2-digit", month: "short" }); } - var labels = trend.map(function (row) { - return dayLabel(row.day); - }); - new Chart(canvas, { type: "line", data: { - labels: labels, + labels: trend.map(function (row) { return dayLabel(row.day); }), datasets: [ { label: i18n.pageviews || "Pageviews", @@ -29,27 +58,6 @@ tension: 0.25, pointRadius: 3, pointHoverRadius: 5 - }, - { - label: i18n.clicks || "Clicks", - data: trend.map(function (r) { return r.clicks || 0; }), - borderColor: "rgba(66, 165, 245, 0.95)", - backgroundColor: "transparent", - fill: false, - tension: 0.25, - pointRadius: 2, - pointHoverRadius: 4 - }, - { - label: i18n.moves || "Moves", - data: trend.map(function (r) { return r.moves || 0; }), - borderColor: "rgba(255, 193, 7, 0.85)", - backgroundColor: "transparent", - fill: false, - tension: 0.25, - pointRadius: 2, - pointHoverRadius: 4, - borderDash: [4, 3] } ] }, @@ -74,7 +82,7 @@ } }, plugins: { - legend: { labels: { color: "#ccc", boxWidth: 12 } } + legend: { display: false } } } }); diff --git a/backend/public/admin.css b/backend/public/admin.css index 8ddf83e..deeefe6 100644 --- a/backend/public/admin.css +++ b/backend/public/admin.css @@ -178,10 +178,31 @@ body.admin-body { margin-top: 0.75rem; } +.admin-analytics-trend__head { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 1rem; + flex-wrap: wrap; +} + +.admin-analytics-trend__head h3 { + margin: 0 0 0.35rem; +} + .admin-analytics-trend__kpi { margin: 0.75rem 0 0; } +.admin-analytics-trend.is-collapsed .admin-analytics-trend__head { + margin-bottom: 0; +} + +.admin-analytics-pages-title { + margin: 0 0 0.35rem; + font-size: 1rem; +} + .admin-panels { display: grid; grid-template-columns: 1.4fr 1fr; diff --git a/backend/spec/requests/admin/analytics_spec.rb b/backend/spec/requests/admin/analytics_spec.rb index 218614a..55dc6fd 100644 --- a/backend/spec/requests/admin/analytics_spec.rb +++ b/backend/spec/requests/admin/analytics_spec.rb @@ -7,6 +7,8 @@ RSpec.describe "Admin analytics", type: :request do before do post admin_login_path, params: { username: admin.username, password: "Password123" } + AnalyticsPageStat.delete_all + AnalyticsPageCell.delete_all AnalyticsPageStat.create!( day: Time.zone.today, page_path: "/prezzi", @@ -35,9 +37,12 @@ RSpec.describe "Admin analytics", type: :request do expect(response.body).to include("40") expect(response.body).to include("chart-analytics-trend") expect(response.body).to include("adminAnalyticsTrend") + expect(response.body).to include(I18n.t("admin.analytics.index.hide_chart")) + expect(response.body).to include("hideChart") + expect(response.body).not_to include("clicks:") end - it "mostra il trend anche su più giorni" do + it "il grafico rispetta i filtri data e aggrega pageview di tutte le pagine" do AnalyticsPageStat.create!( day: 1.day.ago.to_date, page_path: "/prezzi", @@ -47,13 +52,25 @@ RSpec.describe "Admin analytics", type: :request do scroll_sum_pct: 0, max_scroll_pct: 0 ) + AnalyticsPageStat.create!( + day: Time.zone.today, + page_path: "/altro", + device: "desktop", + pageview_count: 7, + scroll_samples: 0, + scroll_sum_pct: 0, + max_scroll_pct: 0 + ) get admin_analytics_path, params: { from: 2.days.ago.to_date, to: Time.zone.today } expect(response).to have_http_status(:ok) + expect(response.body).to include(I18n.t("admin.analytics.index.trend_total_label")) + expect(response.body).to include(">24<") expect(response.body).to include("\"pageviews\":5") - expect(response.body).to include("\"pageviews\":12") + expect(response.body).to include("\"pageviews\":19") end + it "mostra la heatmap di una pagina con tab dispositivo" do get admin_analytics_page_path, params: { page_path: "/prezzi" } expect(response).to have_http_status(:ok)