add dashboard filtering to analytics
All checks were successful
deploy / deploy (push) Successful in 1m19s
All checks were successful
deploy / deploy (push) Successful in 1m19s
Click any row in pages, sources, countries, or devices tables to filter the entire dashboard by that dimension. Active filters show as dismissible chips. Filters thread through all queries including previous-period deltas. 1050 tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -231,6 +231,62 @@ defmodule Berrypod.AnalyticsTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering" do
|
||||
test "count_visitors respects country_code filter" do
|
||||
v1 = :crypto.strong_rand_bytes(8)
|
||||
v2 = :crypto.strong_rand_bytes(8)
|
||||
|
||||
insert_event(%{visitor_hash: v1, country_code: "GB"})
|
||||
insert_event(%{visitor_hash: v2, country_code: "US"})
|
||||
|
||||
assert Analytics.count_visitors(today_range(), %{country_code: "GB"}) == 1
|
||||
end
|
||||
|
||||
test "top_pages respects referrer_source filter" do
|
||||
v1 = :crypto.strong_rand_bytes(8)
|
||||
v2 = :crypto.strong_rand_bytes(8)
|
||||
|
||||
insert_event(%{visitor_hash: v1, pathname: "/", referrer_source: "Google"})
|
||||
insert_event(%{visitor_hash: v2, pathname: "/about", referrer_source: "Facebook"})
|
||||
|
||||
pages = Analytics.top_pages(today_range(), filters: %{referrer_source: "Google"})
|
||||
assert length(pages) == 1
|
||||
assert hd(pages).pathname == "/"
|
||||
end
|
||||
|
||||
test "bounce_rate respects filter" do
|
||||
s1 = :crypto.strong_rand_bytes(8)
|
||||
s2 = :crypto.strong_rand_bytes(8)
|
||||
|
||||
# GB visitor bounces (1 pageview)
|
||||
insert_event(%{session_hash: s1, country_code: "GB"})
|
||||
# US visitor doesn't bounce (2 pageviews)
|
||||
insert_event(%{session_hash: s2, country_code: "US", pathname: "/"})
|
||||
insert_event(%{session_hash: s2, country_code: "US", pathname: "/about"})
|
||||
|
||||
assert Analytics.bounce_rate(today_range(), %{country_code: "GB"}) == 100
|
||||
assert Analytics.bounce_rate(today_range(), %{country_code: "US"}) == 0
|
||||
end
|
||||
|
||||
test "multiple filters combine with AND logic" do
|
||||
v1 = :crypto.strong_rand_bytes(8)
|
||||
v2 = :crypto.strong_rand_bytes(8)
|
||||
|
||||
insert_event(%{visitor_hash: v1, country_code: "GB", browser: "Chrome"})
|
||||
insert_event(%{visitor_hash: v2, country_code: "GB", browser: "Firefox"})
|
||||
|
||||
assert Analytics.count_visitors(today_range(), %{country_code: "GB", browser: "Chrome"}) ==
|
||||
1
|
||||
end
|
||||
|
||||
test "unknown filter keys are ignored" do
|
||||
v1 = :crypto.strong_rand_bytes(8)
|
||||
insert_event(%{visitor_hash: v1})
|
||||
|
||||
assert Analytics.count_visitors(today_range(), %{nonexistent: "val"}) == 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_events_before/1" do
|
||||
test "deletes old events" do
|
||||
old = DateTime.add(DateTime.utc_now(), -400, :day) |> DateTime.truncate(:second)
|
||||
|
||||
Reference in New Issue
Block a user