From 085d8e87e26f0d864be402b015402811c976a84b Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Wed, 1 Oct 2025 15:39:08 +0100 Subject: [PATCH 1/7] fix crm team tabs hover bg on darkmode --- extra/lib/plausible_web/live/customer_support/live.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extra/lib/plausible_web/live/customer_support/live.ex b/extra/lib/plausible_web/live/customer_support/live.ex index fecf2f8b7743..363838b0277c 100644 --- a/extra/lib/plausible_web/live/customer_support/live.ex +++ b/extra/lib/plausible_web/live/customer_support/live.ex @@ -4,7 +4,7 @@ defmodule PlausibleWeb.CustomerSupport.Live do Provides: - Standard mount/3 and handle_info/2 implementations - - Tab navigation components and routing utilities + - Tab navigation components and routing utilities - Common aliases and imports for Customer Support LiveViews - Convenience API for flashes and redirects """ @@ -84,7 +84,7 @@ defmodule PlausibleWeb.CustomerSupport.Live do patch={"?tab=#{@to}"} class={[ @link_class, - "group relative min-w-0 flex-1 overflow-hidden bg-white dark:bg-gray-800 py-4 px-6 text-center text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-750 focus:z-10 first:rounded-l-lg last:rounded-r-lg" + "group relative min-w-0 flex-1 overflow-hidden bg-white dark:bg-gray-800 py-4 px-6 text-center text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-700 focus:z-10 first:rounded-l-lg last:rounded-r-lg" ]} > {render_slot(@inner_block)} From 54ffc0d5169f95772f25881a0980926b0ef126ff Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Wed, 1 Oct 2025 15:51:07 +0100 Subject: [PATCH 2/7] add settings link to consolidated views cs page --- .../team/components/consolidated_views.ex | 16 ++++++++++++++++ .../live/customer_support/teams_test.exs | 1 + 2 files changed, 17 insertions(+) diff --git a/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex b/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex index 2e43bd811986..335c5a7f463a 100644 --- a/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex +++ b/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex @@ -29,6 +29,7 @@ defmodule PlausibleWeb.CustomerSupport.Team.Components.ConsolidatedViews do <.th>Domain <.th>Timezone <.th invisible>Dashboard + <.th invisible>Settings <.th invisible>Delete @@ -43,6 +44,21 @@ defmodule PlausibleWeb.CustomerSupport.Team.Components.ConsolidatedViews do Dashboard + <.td> + <.styled_link + new_tab={true} + href={ + Routes.site_path( + PlausibleWeb.Endpoint, + :settings_general, + consolidated_view.domain, + [] + ) + } + > + Settings + + <.td> <.delete_button phx-click="delete-consolidated-view" diff --git a/test/plausible_web/live/customer_support/teams_test.exs b/test/plausible_web/live/customer_support/teams_test.exs index 305c5c8c4463..f718b6e0bc8d 100644 --- a/test/plausible_web/live/customer_support/teams_test.exs +++ b/test/plausible_web/live/customer_support/teams_test.exs @@ -218,6 +218,7 @@ defmodule PlausibleWeb.Live.CustomerSupport.TeamsTest do assert table_text =~ team.identifier assert table_text =~ "Dashboard" + assert table_text =~ "Settings" assert element_exists?(html, @delete_consolidated_view_button) end From 497432c31c7e6a7b2089febc1cbeef3478d8bd1f Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Wed, 1 Oct 2025 15:51:27 +0100 Subject: [PATCH 3/7] render error reason in flash message (cs) --- .../customer_support/team/components/consolidated_views.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex b/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex index 335c5a7f463a..4d469eb721d9 100644 --- a/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex +++ b/extra/lib/plausible_web/live/customer_support/team/components/consolidated_views.ex @@ -79,8 +79,8 @@ defmodule PlausibleWeb.CustomerSupport.Team.Components.ConsolidatedViews do success("Consolidated view created") {:noreply, assign(socket, consolidated_views: [consolidated_view])} - {:error, _} -> - failure("Could not create consolidated view") + {:error, reason} -> + failure("Could not create consolidated view. Reason: #{inspect(reason)}") {:noreply, socket} end end From 6e84cbc360a13811f0eb96bfc3a43d7dab6b4b8d Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Wed, 1 Oct 2025 18:12:18 +0100 Subject: [PATCH 4/7] exclude whole sections in consolidated site settings --- lib/plausible_web/views/layout_view.ex | 42 ++++++++++++------- .../controllers/site_controller_test.exs | 24 +++++++++++ 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/lib/plausible_web/views/layout_view.ex b/lib/plausible_web/views/layout_view.ex index 3840f01fd97a..b966bbd1e183 100644 --- a/lib/plausible_web/views/layout_view.ex +++ b/lib/plausible_web/views/layout_view.ex @@ -52,29 +52,41 @@ defmodule PlausibleWeb.LayoutView do end def site_settings_sidebar(conn) do + regular_site? = Plausible.Sites.regular?(conn.assigns.site) + [ %{key: "General", value: "general", icon: :rocket_launch}, - %{key: "People", value: "people", icon: :users}, - %{key: "Visibility", value: "visibility", icon: :eye}, + if regular_site? do + %{key: "People", value: "people", icon: :users} + end, + if regular_site? do + %{key: "Visibility", value: "visibility", icon: :eye} + end, %{key: "Goals", value: "goals", icon: :check_circle}, on_ee do - %{key: "Funnels", value: "funnels", icon: :funnel} + if regular_site? do + %{key: "Funnels", value: "funnels", icon: :funnel} + end end, %{key: "Custom properties", value: "properties", icon: :document_text}, %{key: "Integrations", value: "integrations", icon: :puzzle_piece}, - %{key: "Imports & exports", value: "imports-exports", icon: :arrow_down_tray}, - %{ - key: "Shields", - icon: :shield_exclamation, - value: [ - %{key: "IP addresses", value: "shields/ip_addresses"}, - %{key: "Countries", value: "shields/countries"}, - %{key: "Pages", value: "shields/pages"}, - %{key: "Hostnames", value: "shields/hostnames"} - ] - }, + if regular_site? do + %{key: "Imports & exports", value: "imports-exports", icon: :arrow_down_tray} + end, + if regular_site? do + %{ + key: "Shields", + icon: :shield_exclamation, + value: [ + %{key: "IP addresses", value: "shields/ip_addresses"}, + %{key: "Countries", value: "shields/countries"}, + %{key: "Pages", value: "shields/pages"}, + %{key: "Hostnames", value: "shields/hostnames"} + ] + } + end, %{key: "Email reports", value: "email-reports", icon: :envelope}, - if conn.assigns[:site_role] in [:owner, :admin] do + if regular_site? and conn.assigns[:site_role] in [:owner, :admin] do %{key: "Danger zone", value: "danger-zone", icon: :exclamation_triangle} end ] diff --git a/test/plausible_web/controllers/site_controller_test.exs b/test/plausible_web/controllers/site_controller_test.exs index cb89dd73926b..d28d30d44496 100644 --- a/test/plausible_web/controllers/site_controller_test.exs +++ b/test/plausible_web/controllers/site_controller_test.exs @@ -575,6 +575,30 @@ defmodule PlausibleWeb.SiteControllerTest do ] end + @tag :ee_only + test "consolidated view settings sidebar items", %{ + conn: conn, + user: user + } do + team = user |> team_of() + site = new_consolidated_view(team) + conn = get(conn, "/#{site.domain}/settings/general") + resp = html_response(conn, 200) + + items = + resp + |> find("[data-testid=site_settings_sidebar] a") + |> Enum.map(fn a -> {text(a), text_of_attr(a, "href")} end) + + assert items == [ + {"General", "/#{site.domain}/settings/general"}, + {"Goals", "/#{site.domain}/settings/goals"}, + {"Custom properties", "/#{site.domain}/settings/properties"}, + {"Integrations", "/#{site.domain}/settings/integrations"}, + {"Email reports", "/#{site.domain}/settings/email-reports"} + ] + end + test "header and footer are shown", %{conn: conn, site: site, user: user} do conn = get(conn, "/#{site.domain}/settings/general") resp = html_response(conn, 200) From 8cc2352f7a250b3ccf1dc209796697b107b7298a Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Thu, 2 Oct 2025 11:03:54 +0100 Subject: [PATCH 5/7] filter settings general --- lib/plausible_web/components/generic.ex | 2 +- .../templates/site/settings_general.html.heex | 4 ++-- .../controllers/site_controller_test.exs | 23 +++++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/plausible_web/components/generic.ex b/lib/plausible_web/components/generic.ex index 4e3586e18996..624ed39783df 100644 --- a/lib/plausible_web/components/generic.ex +++ b/lib/plausible_web/components/generic.ex @@ -484,7 +484,7 @@ defmodule PlausibleWeb.Components.Generic do def tile(assigns) do ~H""" -
+
<.title> {render_slot(@title)} diff --git a/lib/plausible_web/templates/site/settings_general.html.heex b/lib/plausible_web/templates/site/settings_general.html.heex index c2cfede05a03..3b0ec52d599a 100644 --- a/lib/plausible_web/templates/site/settings_general.html.heex +++ b/lib/plausible_web/templates/site/settings_general.html.heex @@ -1,5 +1,5 @@ <.settings_tiles> - <.tile docs="change-domain-name"> + <.tile :if={Plausible.Sites.regular?(@site)} docs="change-domain-name"> <:title> Site domain @@ -30,7 +30,7 @@ - <.tile docs="plausible-script"> + <.tile :if={Plausible.Sites.regular?(@site)} docs="plausible-script"> <:title>Site installation <:subtitle> Control what data is collected and verify your installation. diff --git a/test/plausible_web/controllers/site_controller_test.exs b/test/plausible_web/controllers/site_controller_test.exs index d28d30d44496..d41080d66fba 100644 --- a/test/plausible_web/controllers/site_controller_test.exs +++ b/test/plausible_web/controllers/site_controller_test.exs @@ -510,6 +510,16 @@ defmodule PlausibleWeb.SiteControllerTest do assert resp =~ "Site installation" end + @tag :ee_only + test "renders only timezone section for a consolidated site", %{conn: conn, user: user} do + consolidated_view = user |> team_of() |> new_consolidated_view() + conn = get(conn, "/#{consolidated_view.domain}/settings/general") + resp = html_response(conn, 200) + + assert [tile_element] = find(resp, ~s|div[data-test-id="settings-tile"]|) + assert text(tile_element) =~ "Site timezone" + end + @tag :ee_only test "all site settings sidebar items are working links", %{ conn: conn, @@ -1885,6 +1895,19 @@ defmodule PlausibleWeb.SiteControllerTest do end end + describe "/:domain/settings/general" do + setup [:create_user, :log_in] + + test "shows domain change in the settings form", %{conn: conn, site: site} do + conn = get(conn, Routes.site_path(conn, :settings_general, site.domain)) + resp = html_response(conn, 200) + + assert resp =~ "Site domain" + assert resp =~ "Change domain" + assert resp =~ Routes.site_path(conn, :change_domain, site.domain) + end + end + describe "domain change" do setup [:create_user, :log_in, :create_site] From b429e015917e2a72424c3cb5d2ab2351dac171cb Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Sun, 5 Oct 2025 12:04:19 +0100 Subject: [PATCH 6/7] make goal settings work + tests --- lib/plausible_web/live/goal_settings.ex | 5 +- .../plausible_web/live/goal_settings_test.exs | 83 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/lib/plausible_web/live/goal_settings.ex b/lib/plausible_web/live/goal_settings.ex index b95c2d092b00..91a8c5340af4 100644 --- a/lib/plausible_web/live/goal_settings.ex +++ b/lib/plausible_web/live/goal_settings.ex @@ -16,7 +16,10 @@ defmodule PlausibleWeb.Live.GoalSettings do socket |> assign_new(:site, fn %{current_user: current_user} -> current_user - |> Plausible.Sites.get_for_user!(domain, roles: [:owner, :admin, :editor, :super_admin]) + |> Plausible.Sites.get_for_user!(domain, + roles: [:owner, :admin, :editor, :super_admin], + include_consolidated?: true + ) end) |> assign_new(:site_role, fn %{site: site, current_user: current_user} -> if Plausible.Auth.is_super_admin?(current_user) do diff --git a/test/plausible_web/live/goal_settings_test.exs b/test/plausible_web/live/goal_settings_test.exs index 060ed21ce76c..6f2d425febab 100644 --- a/test/plausible_web/live/goal_settings_test.exs +++ b/test/plausible_web/live/goal_settings_test.exs @@ -98,6 +98,44 @@ defmodule PlausibleWeb.Live.GoalSettingsTest do end end + on_ee do + describe "GET /:domain/settings/goals - consolidated views" do + setup [:create_user, :create_team, :log_in] + + setup %{team: team} = context do + new_site(team: team) + new_site(team: team) + + {:ok, Map.put(context, :consolidated_view, new_consolidated_view(team))} + end + + test "no goals exist", %{conn: conn, consolidated_view: consolidated_view} do + conn = get(conn, "/#{consolidated_view.domain}/settings/goals") + + assert resp = html_response(conn, 200) + assert resp =~ "Define actions that you want your users to take" + assert resp =~ "No goals configured for this site" + assert element_exists?(resp, ~s|a[href="https://plausible.io/docs/goal-conversions"]|) + end + + test "lists goals", %{conn: conn, consolidated_view: consolidated_view} do + {:ok, g1} = Plausible.Goals.create(consolidated_view, %{"page_path" => "/go/to/blog/**"}) + {:ok, g2} = Plausible.Goals.create(consolidated_view, %{"event_name" => "Register"}) + + conn = get(conn, "/#{consolidated_view.domain}/settings/goals") + + assert resp = html_response(conn, 200) + assert resp =~ "Define actions that you want your users to take" + assert element_exists?(resp, ~s|a[href="https://plausible.io/docs/goal-conversions"]|) + + assert resp =~ to_string(g1) + assert resp =~ "Pageview" + assert resp =~ to_string(g2) + assert resp =~ "Custom Event" + end + end + end + describe "GoalSettings live view" do setup [:create_user, :log_in, :create_site] @@ -213,6 +251,51 @@ defmodule PlausibleWeb.Live.GoalSettingsTest do end end + describe "GoalSettings live view - consolidated views" do + setup [:create_user, :create_team, :log_in] + + setup %{team: team} = context do + new_site(team: team) + new_site(team: team) + + {:ok, Map.put(context, :consolidated_view, new_consolidated_view(team))} + end + + test "allows goal deletion", %{conn: conn, consolidated_view: consolidated_view} do + {:ok, g1} = Plausible.Goals.create(consolidated_view, %{"page_path" => "/go/to/blog/**"}) + {:ok, g2} = Plausible.Goals.create(consolidated_view, %{"event_name" => "Register"}) + + {lv, html} = get_liveview(conn, consolidated_view, with_html?: true) + + assert html =~ to_string(g1) + assert html =~ to_string(g2) + + html = lv |> element(~s/button#delete-goal-#{g1.id}/) |> render_click() + + refute html =~ to_string(g1) + assert html =~ to_string(g2) + + html = get(conn, "/#{consolidated_view.domain}/settings/goals") |> html_response(200) + + refute html =~ to_string(g1) + assert html =~ to_string(g2) + end + + test "allows list filtering / search", %{conn: conn, consolidated_view: consolidated_view} do + {:ok, g1} = Plausible.Goals.create(consolidated_view, %{"page_path" => "/go/to/blog/**"}) + {:ok, g2} = Plausible.Goals.create(consolidated_view, %{"event_name" => "Register"}) + {lv, html} = get_liveview(conn, consolidated_view, with_html?: true) + + assert html =~ to_string(g1) + assert html =~ to_string(g2) + + html = type_into_search(lv, to_string(g2)) + + refute html =~ to_string(g1) + assert html =~ to_string(g2) + end + end + defp setup_goals(site) do {:ok, g1} = Plausible.Goals.create(site, %{"page_path" => "/go/to/blog/**"}) {:ok, g2} = Plausible.Goals.create(site, %{"event_name" => "Register"}) From 7c48582d5551c2836d93ffc34791dd0152d3908a Mon Sep 17 00:00:00 2001 From: Robert Joonas Date: Sun, 5 Oct 2025 12:17:20 +0100 Subject: [PATCH 7/7] do not render funnels cta --- .../templates/site/settings_goals.html.heex | 2 +- test/plausible_web/live/goal_settings_test.exs | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/plausible_web/templates/site/settings_goals.html.heex b/lib/plausible_web/templates/site/settings_goals.html.heex index 8b58b585cd02..309295d0367f 100644 --- a/lib/plausible_web/templates/site/settings_goals.html.heex +++ b/lib/plausible_web/templates/site/settings_goals.html.heex @@ -13,7 +13,7 @@

Define actions that you want your users to take, like visiting a certain page, submitting a form, etc.

-

+

You can also <.styled_link href={Routes.site_path(@conn, :settings_funnels, @site.domain)}> compose goals into funnels. diff --git a/test/plausible_web/live/goal_settings_test.exs b/test/plausible_web/live/goal_settings_test.exs index 6f2d425febab..496bc0f9fbb6 100644 --- a/test/plausible_web/live/goal_settings_test.exs +++ b/test/plausible_web/live/goal_settings_test.exs @@ -4,6 +4,8 @@ defmodule PlausibleWeb.Live.GoalSettingsTest do import Phoenix.LiveViewTest import Plausible.Test.Support.HTML + @funnels_cta ~s|p[data-test-id="setup-funnels-cta"]| + describe "GET /:domain/settings/goals" do setup [:create_user, :log_in, :create_site] @@ -14,8 +16,11 @@ defmodule PlausibleWeb.Live.GoalSettingsTest do resp = html_response(conn, 200) assert resp =~ "Define actions that you want your users to take" - assert resp =~ "compose goals into funnels" - assert resp =~ "/#{URI.encode_www_form(site.domain)}/settings/funnels" + assert text_of_element(resp, @funnels_cta) =~ "compose goals into funnels" + + assert text_of_element(resp, @funnels_cta) =~ + "/#{URI.encode_www_form(site.domain)}/settings/funnels" + assert element_exists?(resp, ~s|a[href="https://plausible.io/docs/goal-conversions"]|) assert resp =~ to_string(g1) @@ -133,6 +138,13 @@ defmodule PlausibleWeb.Live.GoalSettingsTest do assert resp =~ to_string(g2) assert resp =~ "Custom Event" end + + test "does not render funnels cta", %{conn: conn, consolidated_view: consolidated_view} do + conn = get(conn, "/#{consolidated_view.domain}/settings/goals") + + assert resp = html_response(conn, 200) + refute element_exists?(resp, @funnels_cta) + end end end