From 1a6fc3063ecc2261dfa101fb751f5cf860b6843d Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Mon, 2 Mar 2026 14:13:09 +0100 Subject: [PATCH 1/7] Add dashboard links to monthly pageview usage breakdown - On the subscription settings page, each billing period's "Total billable pageviews" row and each individual site in the breakdown now show an external link icon that deep-links to the dashboard filtered to that exact billing cycle date range. - For the total link, the consolidated view domain is preferred when available; otherwise the site's own domain is used when the team has exactly one site. --- .../components/billing/billing.ex | 72 +++++++++++++++- .../controllers/settings_controller.ex | 25 +++++- .../templates/settings/subscription.html.heex | 3 + .../components/billing/billing_test.exs | 85 ++++++++++++++++++- .../controllers/settings_controller_test.exs | 51 +++++++++++ 5 files changed, 232 insertions(+), 4 deletions(-) diff --git a/lib/plausible_web/components/billing/billing.ex b/lib/plausible_web/components/billing/billing.ex index 95bc7a1116a7..de9abd89bf9b 100644 --- a/lib/plausible_web/components/billing/billing.ex +++ b/lib/plausible_web/components/billing/billing.ex @@ -4,6 +4,8 @@ defmodule PlausibleWeb.Components.Billing do use PlausibleWeb, :component use Plausible + import PlausibleWeb.Components.Icons + require Plausible.Billing.Subscription.Status alias Plausible.Billing.{Plan, Plans, EnterprisePlan} @@ -49,6 +51,12 @@ defmodule PlausibleWeb.Components.Billing do """ end + attr :usage, :map, required: true + attr :limit, :any, required: true + attr :consolidated_view_domain, :string, default: nil + attr :site_domain, :string, default: nil + attr :team_identifier, :string, default: nil + def render_monthly_pageview_usage(%{usage: usage} = assigns) when is_map_key(usage, :last_30_days) do ~H""" @@ -57,6 +65,9 @@ defmodule PlausibleWeb.Components.Billing do limit={@limit} period={:last_30_days} expanded={true} + consolidated_view_domain={@consolidated_view_domain} + site_domain={@site_domain} + team_identifier={@team_identifier} /> """ end @@ -76,6 +87,9 @@ defmodule PlausibleWeb.Components.Billing do limit={@limit} period={:current_cycle} expanded={not @show_all and Enum.empty?(@usage.current_cycle.sites)} + consolidated_view_domain={@consolidated_view_domain} + site_domain={@site_domain} + team_identifier={@team_identifier} /> <%= if @show_all do %> <.monthly_pageview_usage_breakdown @@ -83,12 +97,18 @@ defmodule PlausibleWeb.Components.Billing do limit={@limit} period={:last_cycle} expanded={false} + consolidated_view_domain={@consolidated_view_domain} + site_domain={@site_domain} + team_identifier={@team_identifier} /> <.monthly_pageview_usage_breakdown usage={@usage.penultimate_cycle} limit={@limit} period={:penultimate_cycle} expanded={false} + consolidated_view_domain={@consolidated_view_domain} + site_domain={@site_domain} + team_identifier={@team_identifier} /> <% end %> @@ -99,8 +119,22 @@ defmodule PlausibleWeb.Components.Billing do attr(:limit, :any, required: true) attr(:period, :atom, required: true) attr(:expanded, :boolean, required: true) + attr(:consolidated_view_domain, :string, default: nil) + attr(:site_domain, :string, default: nil) + attr(:team_identifier, :string, default: nil) defp monthly_pageview_usage_breakdown(assigns) do + assigns = + assign( + assigns, + :total_link, + dashboard_url( + assigns.consolidated_view_domain || assigns.site_domain, + assigns.usage.date_range, + assigns.team_identifier + ) + ) + ~H"""
@@ -120,6 +154,17 @@ defmodule PlausibleWeb.Components.Billing do class="size-4 transition-transform" x-bind:class="open ? 'rotate-90' : ''" /> Total billable pageviews + <.tooltip :if={@total_link} centered?={true}> + <:tooltip_content>View billing period in dashboard + <.link + href={@total_link} + class="text-indigo-500 hover:text-indigo-600" + data-test-id="total-pageviews-dashboard-link" + x-on:click.stop + > + <.external_link_icon class="ml-0.5 size-3.5 [&_path]:stroke-2" /> + + {PlausibleWeb.TextHelpers.number_format(@usage.total)} @@ -146,7 +191,18 @@ defmodule PlausibleWeb.Components.Billing do

0} class="border-gray-200 dark:border-gray-700" />
- {site.domain} + + {site.domain} + <.tooltip centered?={true}> + <:tooltip_content>View billing period in dashboard + <.link + href={dashboard_url(site.domain, @usage.date_range, @team_identifier)} + class="shrink-0 text-indigo-500 hover:text-indigo-600" + > + <.external_link_icon class="ml-0.5 size-3.5 [&_path]:stroke-2" /> + + + {PlausibleWeb.TextHelpers.number_format(site.total)}
<.pageview_usage_row label="Pageviews" value={site.pageviews} /> @@ -174,6 +230,20 @@ defmodule PlausibleWeb.Components.Billing do """ end + defp dashboard_url(nil, _date_range, _team_identifier), do: nil + + defp dashboard_url(domain, date_range, team_identifier) do + base = Routes.stats_path(PlausibleWeb.Endpoint, :stats, domain, []) + + query_string = + "?period=custom&from=#{Date.to_iso8601(date_range.first)}&to=#{Date.to_iso8601(date_range.last)}" + + query_string = + if team_identifier, do: query_string <> "&__team=#{team_identifier}", else: query_string + + base <> query_string + end + defp cycle_label(:current_cycle), do: "(current cycle)" defp cycle_label(:last_30_days), do: "(last 30 days)" diff --git a/lib/plausible_web/controllers/settings_controller.ex b/lib/plausible_web/controllers/settings_controller.ex index 2fdc8d72826d..0882b9b3e414 100644 --- a/lib/plausible_web/controllers/settings_controller.ex +++ b/lib/plausible_web/controllers/settings_controller.ex @@ -152,6 +152,26 @@ defmodule PlausibleWeb.SettingsController do notification_type = Plausible.Billing.Quota.usage_notification_type(team, usage) + site_domain = + if site_usage == 1 do + case Plausible.Teams.owned_sites(team, 1) do + [site | _] -> site.domain + _ -> nil + end + end + + consolidated_view_domain = + on_ee( + do: + if team do + case Plausible.ConsolidatedView.get(team) do + nil -> nil + view -> if Plausible.ConsolidatedView.ok_to_display?(team), do: view.domain + end + end, + else: nil + ) + render(conn, :subscription, layout: {PlausibleWeb.LayoutView, :settings}, subscription: subscription, @@ -162,7 +182,10 @@ defmodule PlausibleWeb.SettingsController do site_limit: Teams.Billing.site_limit(team), team_member_limit: Teams.Billing.team_member_limit(team), team_member_usage: team_member_usage, - notification_type: notification_type + notification_type: notification_type, + consolidated_view_domain: consolidated_view_domain, + site_domain: site_domain, + team_identifier: team && team.identifier ) end diff --git a/lib/plausible_web/templates/settings/subscription.html.heex b/lib/plausible_web/templates/settings/subscription.html.heex index e97f7b17f90c..ca7bb9f13203 100644 --- a/lib/plausible_web/templates/settings/subscription.html.heex +++ b/lib/plausible_web/templates/settings/subscription.html.heex @@ -117,6 +117,9 @@
diff --git a/test/plausible_web/components/billing/billing_test.exs b/test/plausible_web/components/billing/billing_test.exs index cbf9d7ad1f4c..1afc824d446f 100644 --- a/test/plausible_web/components/billing/billing_test.exs +++ b/test/plausible_web/components/billing/billing_test.exs @@ -320,6 +320,78 @@ defmodule PlausibleWeb.Components.BillingTest do refute html =~ "{ open: true }" end + + test "renders a total link when site_domain is provided" do + usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} + + html = render_monthly_pageview_usage(usage, 10_000, site_domain: "my-site.example.com") + + assert element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") + assert html =~ "/my-site.example.com/?period=custom" + end + + test "renders a total link when consolidated_view_domain is provided" do + usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} + + html = + render_monthly_pageview_usage(usage, 10_000, + consolidated_view_domain: "consolidated.example.com" + ) + + assert element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") + assert html =~ "/consolidated.example.com/?period=custom" + end + + test "consolidated_view_domain takes precedence over site_domain for the total link" do + usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} + + html = + render_monthly_pageview_usage(usage, 10_000, + consolidated_view_domain: "consolidated.example.com", + site_domain: "my-site.example.com" + ) + + assert html =~ "/consolidated.example.com/?period=custom" + refute html =~ "/my-site.example.com/?period=custom" + end + + test "renders no total link when no domain is provided" do + usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} + + html = render_monthly_pageview_usage(usage, 10_000) + + refute element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") + end + + test "per-site breakdown shows a dashboard link for each site" do + cycle_with_sites = %{ + @cycle + | sites: [ + %{domain: "example.com", pageviews: 100, custom_events: 50, total: 150}, + %{domain: "app.example.com", pageviews: 200, custom_events: 30, total: 230} + ] + } + + usage = %{current_cycle: cycle_with_sites, last_cycle: @cycle, penultimate_cycle: @cycle} + + html = render_monthly_pageview_usage(usage, 10_000) + + assert html =~ "/example.com/?period=custom" + assert html =~ "/app.example.com/?period=custom" + end + + test "dashboard links include the billing cycle date range and team identifier" do + usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} + + html = + render_monthly_pageview_usage(usage, 10_000, + site_domain: "my-site.example.com", + team_identifier: "my-team-id" + ) + + assert html =~ + "/my-site.example.com/?period=custom&from=2024-01-01&to=2024-01-31&__team=my-team-id" + end end defp render_progress_bar(usage, limit) do @@ -334,13 +406,22 @@ defmodule PlausibleWeb.Components.BillingTest do |> rendered_to_string() end - defp render_monthly_pageview_usage(usage, limit) do - assigns = %{usage: usage, limit: limit} + defp render_monthly_pageview_usage(usage, limit, opts \\ []) do + assigns = %{ + usage: usage, + limit: limit, + consolidated_view_domain: opts[:consolidated_view_domain], + site_domain: opts[:site_domain], + team_identifier: opts[:team_identifier] + } ~H""" """ |> rendered_to_string() diff --git a/test/plausible_web/controllers/settings_controller_test.exs b/test/plausible_web/controllers/settings_controller_test.exs index 48ea0d5287d5..102b54c60b32 100644 --- a/test/plausible_web/controllers/settings_controller_test.exs +++ b/test/plausible_web/controllers/settings_controller_test.exs @@ -532,6 +532,57 @@ defmodule PlausibleWeb.SettingsControllerTest do assert html =~ "Invoices" assert text(html) =~ "We couldn't retrieve your invoices" end + + @tag :ee_only + test "shows dashboard link to the site when team has exactly one site", %{ + conn: conn, + user: user + } do + new_site(owner: user) + + html = + conn + |> get(Routes.settings_path(conn, :subscription)) + |> html_response(200) + + assert element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") + end + + @tag :ee_only + test "shows no total dashboard link when team has multiple sites and no consolidated view", %{ + conn: conn, + user: user + } do + new_site(owner: user) + new_site(owner: user) + + html = + conn + |> get(Routes.settings_path(conn, :subscription)) + |> html_response(200) + + refute element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") + end + + on_ee do + test "shows consolidated view dashboard link when team has a consolidated view", %{ + conn: conn, + user: user + } do + new_site(owner: user) + new_site(owner: user) + team = team_of(user) + new_consolidated_view(team) + + html = + conn + |> set_current_team(team) + |> get(Routes.settings_path(conn, :subscription)) + |> html_response(200) + + assert element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") + end + end end describe "GET /security" do From 86e9eed0afaf24d8af61f10918de6f051d030896 Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Mon, 2 Mar 2026 14:41:54 +0100 Subject: [PATCH 2/7] Fix CI failures from nested consolidated view logic in settings controller --- .../controllers/settings_controller.ex | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/plausible_web/controllers/settings_controller.ex b/lib/plausible_web/controllers/settings_controller.ex index 0882b9b3e414..1f0c5d47d77d 100644 --- a/lib/plausible_web/controllers/settings_controller.ex +++ b/lib/plausible_web/controllers/settings_controller.ex @@ -160,17 +160,7 @@ defmodule PlausibleWeb.SettingsController do end end - consolidated_view_domain = - on_ee( - do: - if team do - case Plausible.ConsolidatedView.get(team) do - nil -> nil - view -> if Plausible.ConsolidatedView.ok_to_display?(team), do: view.domain - end - end, - else: nil - ) + consolidated_view_domain = on_ee(do: get_consolidated_view_domain(team), else: nil) render(conn, :subscription, layout: {PlausibleWeb.LayoutView, :settings}, @@ -484,6 +474,17 @@ defmodule PlausibleWeb.SettingsController do end end + on_ee do + defp get_consolidated_view_domain(nil), do: nil + + defp get_consolidated_view_domain(team) do + case Plausible.ConsolidatedView.get(team) do + nil -> nil + view -> if Plausible.ConsolidatedView.ok_to_display?(team), do: view.domain + end + end + end + defp handle_email_updated(conn) do conn |> put_flash(:success, "Email updated") From d9965d81a90a810c81f17c3d06fc7f2fcf0bebef Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Mon, 2 Mar 2026 14:57:56 +0100 Subject: [PATCH 3/7] Fix Dialyzer CI failure --- lib/plausible_web/controllers/settings_controller.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/plausible_web/controllers/settings_controller.ex b/lib/plausible_web/controllers/settings_controller.ex index 1f0c5d47d77d..cb549f64cec2 100644 --- a/lib/plausible_web/controllers/settings_controller.ex +++ b/lib/plausible_web/controllers/settings_controller.ex @@ -475,8 +475,6 @@ defmodule PlausibleWeb.SettingsController do end on_ee do - defp get_consolidated_view_domain(nil), do: nil - defp get_consolidated_view_domain(team) do case Plausible.ConsolidatedView.get(team) do nil -> nil From 199a459dbd41faf062effe9d07413a4e0d7b522f Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Mon, 2 Mar 2026 15:15:39 +0100 Subject: [PATCH 4/7] Extract consolidated view domain lookup to avoid Dialyzer warning --- lib/plausible_web/controllers/settings_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plausible_web/controllers/settings_controller.ex b/lib/plausible_web/controllers/settings_controller.ex index cb549f64cec2..da3cd9e83496 100644 --- a/lib/plausible_web/controllers/settings_controller.ex +++ b/lib/plausible_web/controllers/settings_controller.ex @@ -160,7 +160,7 @@ defmodule PlausibleWeb.SettingsController do end end - consolidated_view_domain = on_ee(do: get_consolidated_view_domain(team), else: nil) + consolidated_view_domain = on_ee(do: team && get_consolidated_view_domain(team), else: nil) render(conn, :subscription, layout: {PlausibleWeb.LayoutView, :settings}, From 50d5167aaa39f6c70baf5dc182c468fd54860ecb Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Tue, 3 Mar 2026 18:33:12 +0000 Subject: [PATCH 5/7] fix dialyzer --- lib/plausible/teams/billing.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plausible/teams/billing.ex b/lib/plausible/teams/billing.ex index dacf595c6fd5..dd902ff66076 100644 --- a/lib/plausible/teams/billing.ex +++ b/lib/plausible/teams/billing.ex @@ -219,7 +219,7 @@ defmodule Plausible.Teams.Billing do @doc """ Returns the number of sites the given team owns. """ - @spec site_usage(Teams.Team.t()) :: non_neg_integer() + @spec site_usage(Teams.Team.t() | nil) :: non_neg_integer() def site_usage(nil), do: 0 def site_usage(team) do @@ -350,7 +350,7 @@ defmodule Plausible.Teams.Billing do team owns. Alternatively, given an optional argument of `site_ids`, the usage from across all those sites is queried instead. """ - @spec monthly_pageview_usage(Teams.Team.t(), list() | nil) :: monthly_pageview_usage() + @spec monthly_pageview_usage(Teams.Team.t() | nil, list() | nil) :: monthly_pageview_usage() def monthly_pageview_usage(team, site_ids \\ nil) def monthly_pageview_usage(team, nil) do @@ -376,7 +376,7 @@ defmodule Plausible.Teams.Billing do end end - @spec team_member_usage(Teams.Team.t(), Keyword.t()) :: non_neg_integer() + @spec team_member_usage(Teams.Team.t() | nil, Keyword.t()) :: non_neg_integer() @doc """ Returns the total count of team members associated with the team's sites. From 686eec553879ebd8de59bdbd9a33486ef7af1ecd Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Wed, 4 Mar 2026 09:52:26 +0100 Subject: [PATCH 6/7] Incorporate feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Merge `site_domain` and `consolidated_view_domain` into a single`total_pageview_usage_domain` assign, resolving the precedence logic in the controller rather than the component - Rename `sites` to `per_site` in the usage cycle map to distinguish it from the site count field in quota usage - Remove `team_identifier` from controller assigns, template, and billing component — the session already carries the correct team context when the user is on the subscription settings page --- lib/plausible/teams/billing.ex | 4 +- .../components/billing/billing.ex | 52 ++++++------------ .../controllers/settings_controller.ex | 10 ++-- .../templates/settings/subscription.html.heex | 4 +- test/plausible/billing/quota_test.exs | 20 +++---- .../components/billing/billing_test.exs | 53 +++++-------------- 6 files changed, 48 insertions(+), 95 deletions(-) diff --git a/lib/plausible/teams/billing.ex b/lib/plausible/teams/billing.ex index dd902ff66076..b483d56c1323 100644 --- a/lib/plausible/teams/billing.ex +++ b/lib/plausible/teams/billing.ex @@ -430,7 +430,7 @@ defmodule Plausible.Teams.Billing do pageviews: pageviews, custom_events: custom_events, total: pageviews + custom_events, - sites: per_site_usage(owned_site_ids, date_range) + per_site: per_site_usage(owned_site_ids, date_range) } end @@ -470,7 +470,7 @@ defmodule Plausible.Teams.Billing do pageviews: pageviews, custom_events: custom_events, total: pageviews + custom_events, - sites: per_site_usage(owned_site_ids, date_range) + per_site: per_site_usage(owned_site_ids, date_range) } end diff --git a/lib/plausible_web/components/billing/billing.ex b/lib/plausible_web/components/billing/billing.ex index de9abd89bf9b..dc5e503ea57b 100644 --- a/lib/plausible_web/components/billing/billing.ex +++ b/lib/plausible_web/components/billing/billing.ex @@ -53,9 +53,7 @@ defmodule PlausibleWeb.Components.Billing do attr :usage, :map, required: true attr :limit, :any, required: true - attr :consolidated_view_domain, :string, default: nil - attr :site_domain, :string, default: nil - attr :team_identifier, :string, default: nil + attr :total_pageview_usage_domain, :string, default: nil def render_monthly_pageview_usage(%{usage: usage} = assigns) when is_map_key(usage, :last_30_days) do @@ -65,9 +63,7 @@ defmodule PlausibleWeb.Components.Billing do limit={@limit} period={:last_30_days} expanded={true} - consolidated_view_domain={@consolidated_view_domain} - site_domain={@site_domain} - team_identifier={@team_identifier} + total_pageview_usage_domain={@total_pageview_usage_domain} /> """ end @@ -86,10 +82,8 @@ defmodule PlausibleWeb.Components.Billing do usage={@usage.current_cycle} limit={@limit} period={:current_cycle} - expanded={not @show_all and Enum.empty?(@usage.current_cycle.sites)} - consolidated_view_domain={@consolidated_view_domain} - site_domain={@site_domain} - team_identifier={@team_identifier} + expanded={not @show_all and Enum.empty?(@usage.current_cycle.per_site)} + total_pageview_usage_domain={@total_pageview_usage_domain} /> <%= if @show_all do %> <.monthly_pageview_usage_breakdown @@ -97,18 +91,14 @@ defmodule PlausibleWeb.Components.Billing do limit={@limit} period={:last_cycle} expanded={false} - consolidated_view_domain={@consolidated_view_domain} - site_domain={@site_domain} - team_identifier={@team_identifier} + total_pageview_usage_domain={@total_pageview_usage_domain} /> <.monthly_pageview_usage_breakdown usage={@usage.penultimate_cycle} limit={@limit} period={:penultimate_cycle} expanded={false} - consolidated_view_domain={@consolidated_view_domain} - site_domain={@site_domain} - team_identifier={@team_identifier} + total_pageview_usage_domain={@total_pageview_usage_domain} /> <% end %>
@@ -119,9 +109,7 @@ defmodule PlausibleWeb.Components.Billing do attr(:limit, :any, required: true) attr(:period, :atom, required: true) attr(:expanded, :boolean, required: true) - attr(:consolidated_view_domain, :string, default: nil) - attr(:site_domain, :string, default: nil) - attr(:team_identifier, :string, default: nil) + attr(:total_pageview_usage_domain, :string, default: nil) defp monthly_pageview_usage_breakdown(assigns) do assigns = @@ -129,9 +117,8 @@ defmodule PlausibleWeb.Components.Billing do assigns, :total_link, dashboard_url( - assigns.consolidated_view_domain || assigns.site_domain, - assigns.usage.date_range, - assigns.team_identifier + assigns.total_pageview_usage_domain, + assigns.usage.date_range ) ) @@ -175,20 +162,20 @@ defmodule PlausibleWeb.Components.Billing do
<.pageview_usage_row id={"pageviews_#{@period}"} - label={if Enum.empty?(@usage.sites), do: "Pageviews", else: "Total pageviews"} + label={if Enum.empty?(@usage.per_site), do: "Pageviews", else: "Total pageviews"} value={@usage.pageviews} /> <.pageview_usage_row id={"custom_events_#{@period}"} - label={if Enum.empty?(@usage.sites), do: "Custom events", else: "Total custom events"} + label={if Enum.empty?(@usage.per_site), do: "Custom events", else: "Total custom events"} value={@usage.custom_events} />
-
+

0} class="border-gray-200 dark:border-gray-700" />
@@ -196,7 +183,7 @@ defmodule PlausibleWeb.Components.Billing do <.tooltip centered?={true}> <:tooltip_content>View billing period in dashboard <.link - href={dashboard_url(site.domain, @usage.date_range, @team_identifier)} + href={dashboard_url(site.domain, @usage.date_range)} class="shrink-0 text-indigo-500 hover:text-indigo-600" > <.external_link_icon class="ml-0.5 size-3.5 [&_path]:stroke-2" /> @@ -230,18 +217,13 @@ defmodule PlausibleWeb.Components.Billing do """ end - defp dashboard_url(nil, _date_range, _team_identifier), do: nil + defp dashboard_url(nil, _date_range), do: nil - defp dashboard_url(domain, date_range, team_identifier) do + defp dashboard_url(domain, date_range) do base = Routes.stats_path(PlausibleWeb.Endpoint, :stats, domain, []) - query_string = + base <> "?period=custom&from=#{Date.to_iso8601(date_range.first)}&to=#{Date.to_iso8601(date_range.last)}" - - query_string = - if team_identifier, do: query_string <> "&__team=#{team_identifier}", else: query_string - - base <> query_string end defp cycle_label(:current_cycle), do: "(current cycle)" diff --git a/lib/plausible_web/controllers/settings_controller.ex b/lib/plausible_web/controllers/settings_controller.ex index da3cd9e83496..7e954ba7be1f 100644 --- a/lib/plausible_web/controllers/settings_controller.ex +++ b/lib/plausible_web/controllers/settings_controller.ex @@ -152,16 +152,16 @@ defmodule PlausibleWeb.SettingsController do notification_type = Plausible.Billing.Quota.usage_notification_type(team, usage) - site_domain = + total_pageview_usage_domain = if site_usage == 1 do case Plausible.Teams.owned_sites(team, 1) do [site | _] -> site.domain _ -> nil end + else + on_ee(do: team && get_consolidated_view_domain(team), else: nil) end - consolidated_view_domain = on_ee(do: team && get_consolidated_view_domain(team), else: nil) - render(conn, :subscription, layout: {PlausibleWeb.LayoutView, :settings}, subscription: subscription, @@ -173,9 +173,7 @@ defmodule PlausibleWeb.SettingsController do team_member_limit: Teams.Billing.team_member_limit(team), team_member_usage: team_member_usage, notification_type: notification_type, - consolidated_view_domain: consolidated_view_domain, - site_domain: site_domain, - team_identifier: team && team.identifier + total_pageview_usage_domain: total_pageview_usage_domain ) end diff --git a/lib/plausible_web/templates/settings/subscription.html.heex b/lib/plausible_web/templates/settings/subscription.html.heex index ca7bb9f13203..b7a3e563e7e5 100644 --- a/lib/plausible_web/templates/settings/subscription.html.heex +++ b/lib/plausible_web/templates/settings/subscription.html.heex @@ -117,9 +117,7 @@
diff --git a/test/plausible/billing/quota_test.exs b/test/plausible/billing/quota_test.exs index a080d2a97822..2e2ee5770b01 100644 --- a/test/plausible/billing/quota_test.exs +++ b/test/plausible/billing/quota_test.exs @@ -973,15 +973,15 @@ defmodule Plausible.Billing.QuotaTest do build(:event, timestamp: ~N[2023-05-15 00:00:00], name: "pageview") ]) - %{sites: sites} = Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) + %{per_site: per_site} = Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) - assert length(sites) == 2 + assert length(per_site) == 2 assert %{pageviews: 1, custom_events: 1, total: 2} = - Enum.find(sites, &(&1.domain == site1.domain)) + Enum.find(per_site, &(&1.domain == site1.domain)) assert %{pageviews: 1, custom_events: 0, total: 1} = - Enum.find(sites, &(&1.domain == site2.domain)) + Enum.find(per_site, &(&1.domain == site2.domain)) end test "sites with zero events in the period still appear in the breakdown" do @@ -995,12 +995,12 @@ defmodule Plausible.Billing.QuotaTest do build(:event, timestamp: ~N[2023-05-15 00:00:00], name: "pageview") ]) - %{sites: sites} = Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) + %{per_site: per_site} = Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) - assert length(sites) == 2 + assert length(per_site) == 2 assert %{pageviews: 0, custom_events: 0, total: 0} = - Enum.find(sites, &(&1.domain == site2.domain)) + Enum.find(per_site, &(&1.domain == site2.domain)) end test "returns empty sites list when team has only one site" do @@ -1009,7 +1009,8 @@ defmodule Plausible.Billing.QuotaTest do team = team_of(user) today = ~D[2023-06-01] - assert %{sites: []} = Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) + assert %{per_site: []} = + Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) end test "returns empty sites list when team has more than 10 sites" do @@ -1018,7 +1019,8 @@ defmodule Plausible.Billing.QuotaTest do team = team_of(user) today = ~D[2023-06-01] - assert %{sites: []} = Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) + assert %{per_site: []} = + Plausible.Teams.Billing.usage_cycle(team, :last_30_days, nil, today) end end diff --git a/test/plausible_web/components/billing/billing_test.exs b/test/plausible_web/components/billing/billing_test.exs index 1afc824d446f..93ee24f79c3a 100644 --- a/test/plausible_web/components/billing/billing_test.exs +++ b/test/plausible_web/components/billing/billing_test.exs @@ -184,7 +184,7 @@ defmodule PlausibleWeb.Components.BillingTest do custom_events: 0, total: 0, date_range: Date.range(~D[2024-01-01], ~D[2024-01-31]), - sites: [] + per_site: [] } test "only shows current cycle when neither last nor current cycle is exceeded" do @@ -257,7 +257,7 @@ defmodule PlausibleWeb.Components.BillingTest do test "shows 'Total pageviews' and 'Total custom events' labels when per-site breakdown is present" do cycle_with_sites = %{ @cycle - | sites: [ + | per_site: [ %{domain: "example.com", pageviews: 100, custom_events: 50, total: 150}, %{domain: "app.example.com", pageviews: 200, custom_events: 30, total: 230} ] @@ -274,7 +274,7 @@ defmodule PlausibleWeb.Components.BillingTest do test "renders per-site breakdown when sites are present" do cycle_with_sites = %{ @cycle - | sites: [ + | per_site: [ %{domain: "example.com", pageviews: 100, custom_events: 50, total: 150}, %{domain: "app.example.com", pageviews: 200, custom_events: 30, total: 230} ] @@ -308,7 +308,7 @@ defmodule PlausibleWeb.Components.BillingTest do test "current cycle is not expanded by default when per-site breakdown is present" do cycle_with_sites = %{ @cycle - | sites: [ + | per_site: [ %{domain: "example.com", pageviews: 100, custom_events: 50, total: 150}, %{domain: "app.example.com", pageviews: 200, custom_events: 30, total: 230} ] @@ -321,38 +321,16 @@ defmodule PlausibleWeb.Components.BillingTest do refute html =~ "{ open: true }" end - test "renders a total link when site_domain is provided" do - usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} - - html = render_monthly_pageview_usage(usage, 10_000, site_domain: "my-site.example.com") - - assert element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") - assert html =~ "/my-site.example.com/?period=custom" - end - - test "renders a total link when consolidated_view_domain is provided" do + test "renders a total link when total_pageview_usage_domain is provided" do usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} html = render_monthly_pageview_usage(usage, 10_000, - consolidated_view_domain: "consolidated.example.com" + total_pageview_usage_domain: "my-site.example.com" ) assert element_exists?(html, "[data-test-id='total-pageviews-dashboard-link']") - assert html =~ "/consolidated.example.com/?period=custom" - end - - test "consolidated_view_domain takes precedence over site_domain for the total link" do - usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} - - html = - render_monthly_pageview_usage(usage, 10_000, - consolidated_view_domain: "consolidated.example.com", - site_domain: "my-site.example.com" - ) - - assert html =~ "/consolidated.example.com/?period=custom" - refute html =~ "/my-site.example.com/?period=custom" + assert html =~ "/my-site.example.com/?period=custom" end test "renders no total link when no domain is provided" do @@ -366,7 +344,7 @@ defmodule PlausibleWeb.Components.BillingTest do test "per-site breakdown shows a dashboard link for each site" do cycle_with_sites = %{ @cycle - | sites: [ + | per_site: [ %{domain: "example.com", pageviews: 100, custom_events: 50, total: 150}, %{domain: "app.example.com", pageviews: 200, custom_events: 30, total: 230} ] @@ -380,17 +358,16 @@ defmodule PlausibleWeb.Components.BillingTest do assert html =~ "/app.example.com/?period=custom" end - test "dashboard links include the billing cycle date range and team identifier" do + test "dashboard links include the billing cycle date range" do usage = %{current_cycle: @cycle, last_cycle: @cycle, penultimate_cycle: @cycle} html = render_monthly_pageview_usage(usage, 10_000, - site_domain: "my-site.example.com", - team_identifier: "my-team-id" + total_pageview_usage_domain: "my-site.example.com" ) assert html =~ - "/my-site.example.com/?period=custom&from=2024-01-01&to=2024-01-31&__team=my-team-id" + "/my-site.example.com/?period=custom&from=2024-01-01&to=2024-01-31" end end @@ -410,18 +387,14 @@ defmodule PlausibleWeb.Components.BillingTest do assigns = %{ usage: usage, limit: limit, - consolidated_view_domain: opts[:consolidated_view_domain], - site_domain: opts[:site_domain], - team_identifier: opts[:team_identifier] + total_pageview_usage_domain: opts[:total_pageview_usage_domain] } ~H""" """ |> rendered_to_string() From 93c86527e8045bdb415459c24ba96efbe4f9503c Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Wed, 4 Mar 2026 13:09:41 +0100 Subject: [PATCH 7/7] Simplify single-site domain lookup to a strict pattern match --- lib/plausible_web/controllers/settings_controller.ex | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/plausible_web/controllers/settings_controller.ex b/lib/plausible_web/controllers/settings_controller.ex index 7e954ba7be1f..aa39e396ad04 100644 --- a/lib/plausible_web/controllers/settings_controller.ex +++ b/lib/plausible_web/controllers/settings_controller.ex @@ -154,10 +154,8 @@ defmodule PlausibleWeb.SettingsController do total_pageview_usage_domain = if site_usage == 1 do - case Plausible.Teams.owned_sites(team, 1) do - [site | _] -> site.domain - _ -> nil - end + [site] = Plausible.Teams.owned_sites(team) + site.domain else on_ee(do: team && get_consolidated_view_domain(team), else: nil) end