diff --git a/backend/endpoints/dump.go b/backend/endpoints/dump.go index c53f49ff6..daacfe3a8 100644 --- a/backend/endpoints/dump.go +++ b/backend/endpoints/dump.go @@ -108,8 +108,16 @@ func init() { utcOffset := ctx.ParseUTCOffset("utcoffset") sessionlessUserId := ctx.GetSessionlessUserId() userId := ctx.GetUserId() + var user models.User meta := map[string]string{} + + // Read project parameter from URL + projectFromUrl := ctx.R.FormValue("project") + if projectFromUrl != "" { + meta["project"] = projectFromUrl + } + if ctx.R.FormValue("demo") != "" { user = ctx.User("counter") // counter is the magic demo user meta = map[string]string{"demo": "1"} diff --git a/static/components/dashboard/selector.js b/static/components/dashboard/selector.js index 31e24f159..1567ccec5 100644 --- a/static/components/dashboard/selector.js +++ b/static/components/dashboard/selector.js @@ -4,9 +4,21 @@ customElements.define( constructor() { super(); this.last_sites = null; + document.addEventListener("selector-daterange-fetched", (evt) => { this.handleDateRangeFetched(evt.detail); }); + + // Handle browser back/forward + window.addEventListener("popstate", (evt) => { + if (evt.state && evt.state.site) { + const select = document.getElementById("site-select"); + if (select) { + select.value = evt.state.site; + this.onSiteSelChanged(false); // Skip pushState for popstate navigation + } + } + }); } draw(dump) { @@ -14,7 +26,7 @@ customElements.define( // all other components this.dump = dump; - var sites = Object.entries(dump.sites) + let sites = Object.entries(dump.sites) .sort((a, b) => b[1].count - a[1].count) .map((i) => i[0]); @@ -29,8 +41,9 @@ customElements.define( sites = ["counter.dev"]; } - var sitePref = dump.user.prefs.site; - var rangePref = dump.user.prefs.range; + // Use meta.project if available (from URL parameter), otherwise use prefs.site + let sitePref = dump.meta.project || dump.user.prefs.site; + const rangePref = dump.user.prefs.range; this.style.display = "flex"; @@ -63,7 +76,7 @@ customElements.define( favicon.src = `https://icons.duckduckgo.com/ip3/${this.site}.ico`; } - onSiteSelChanged(evt) { + onSiteSelChanged(updateHistory = true) { this.updateFavicon(); // request change up in the cloud and then also apply that change down @@ -71,6 +84,13 @@ customElements.define( fetch("/setPrefSite?" + encodeURIComponent(this.site)); this.dump.user.prefs.site = this.site; + // Update URL with project parameter (skip for popstate navigation) + if (updateHistory) { + const newUrl = new URL(window.location); + newUrl.searchParams.set("project", this.site); + window.history.pushState({site: this.site}, "", newUrl); + } + document.dispatchEvent( new CustomEvent("redraw", { detail: this.dump, diff --git a/static/js/dashboard.js b/static/js/dashboard.js index 4abcff53c..41cf82dec 100644 --- a/static/js/dashboard.js +++ b/static/js/dashboard.js @@ -22,7 +22,7 @@ Chart.defaults.global.tooltips = { }, }; Chart.defaults.global.tooltips.callbacks.label = function (tooltipItem, data) { - var value = data.datasets[0].data[tooltipItem.index]; + const value = data.datasets[0].data[tooltipItem.index]; return numberFormat(value); }; @@ -37,9 +37,8 @@ function getSelectorEl() { return; } } -selector = getSelectorEl(); // very import element - -allConnectedData = []; +const selector = getSelectorEl(); // very important element +const allConnectedData = []; function connectData(selector, getData) { Array.from(document.querySelectorAll(selector)).forEach((el) => { allConnectedData.push([el, getData]);