From 9ccce04f12617681eab09a3878b5627abcd517ee Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Wed, 5 Nov 2025 17:04:06 +0100 Subject: [PATCH 1/8] Updated empty states across settings --- .../lib/plausible_web/live/funnel_settings.ex | 12 +- .../live/funnel_settings/list.ex | 39 ++-- lib/plausible_web/components/site/feature.ex | 2 +- .../controllers/site_controller.ex | 47 +++++ lib/plausible_web/live/goal_settings/list.ex | 53 +++-- .../live/imports_exports_settings.ex | 89 ++++++--- .../live/plugins/api/settings.ex | 21 +- lib/plausible_web/live/props_settings/list.ex | 40 ++-- .../live/shared_link_settings.ex | 116 ++++++----- .../live/shields/country_rules.ex | 157 ++++++++------- .../live/shields/hostname_rules.ex | 170 ++++++++-------- lib/plausible_web/live/shields/ip_rules.ex | 183 ++++++++++-------- lib/plausible_web/live/shields/page_rules.ex | 163 +++++++++------- .../templates/settings/api_keys.html.heex | 100 +++++----- .../templates/site/settings_funnels.html.heex | 4 +- .../templates/site/settings_goals.html.heex | 2 +- .../site/settings_imports_exports.html.heex | 2 +- .../site/settings_integrations.html.heex | 2 +- .../templates/site/settings_props.html.heex | 2 +- .../site/settings_visibility.html.heex | 4 +- 20 files changed, 726 insertions(+), 482 deletions(-) diff --git a/extra/lib/plausible_web/live/funnel_settings.ex b/extra/lib/plausible_web/live/funnel_settings.ex index 99ea3189db75..93e2189de693 100644 --- a/extra/lib/plausible_web/live/funnel_settings.ex +++ b/extra/lib/plausible_web/live/funnel_settings.ex @@ -70,15 +70,15 @@ defmodule PlausibleWeb.Live.FunnelSettings do /> -
-

+
+

Ready to dig into user flows? -

-

- Set up a few goals first (e.g. "Signup", "Visit /", or "Scroll 50% on /blog/*") and return here to build your first funnel! +

+

+ Set up a few goals like Signup, Visit /, or Scroll 50% on /blog/* first, then return here to build your first funnel.

<.button_link - class="mb-2" + class="mt-4" href={PlausibleWeb.Router.Helpers.site_path(@socket, :settings_goals, @domain)} > Set up goals → diff --git a/extra/lib/plausible_web/live/funnel_settings/list.ex b/extra/lib/plausible_web/live/funnel_settings/list.ex index 008756911647..0e777aa3982c 100644 --- a/extra/lib/plausible_web/live/funnel_settings/list.ex +++ b/extra/lib/plausible_web/live/funnel_settings/list.ex @@ -12,11 +12,13 @@ defmodule PlausibleWeb.Live.FunnelSettings.List do def render(assigns) do ~H"""
- <.filter_bar filter_text={@filter_text} placeholder="Search Funnels"> - <.button id="add-funnel-button" phx-click="add-funnel" mt?={false}> - Add funnel - - + <%= if String.trim(@filter_text) != "" || Enum.count(@funnels) > 0 do %> + <.filter_bar filter_text={@filter_text} placeholder="Search Funnels"> + <.button id="add-funnel-button" phx-click="add-funnel" mt?={false}> + Add funnel + + + <% end %> <%= if Enum.count(@funnels) > 0 do %> <.table rows={@funnels}> @@ -42,17 +44,30 @@ defmodule PlausibleWeb.Live.FunnelSettings.List do <% else %> -

- + <%= if String.trim(@filter_text) != "" do %> +

No funnels found for this site. Please refine or <.styled_link phx-click="reset-filter-text" id="reset-filter-hint"> reset your search. - - - No funnels configured for this site. - -

+

+ <% else %> +
+

+ Create your first funnel +

+

+ Compose goals into funnels to track user flows and conversion rates. <.styled_link href="https://plausible.io/docs/funnel-analysis" target="_blank">Learn more +

+ <.button + id="add-funnel-button" + phx-click="add-funnel" + class="mt-4" + > + Add funnel + +
+ <% end %> <% end %>
""" diff --git a/lib/plausible_web/components/site/feature.ex b/lib/plausible_web/components/site/feature.ex index 4976f9f93cec..2bc74a55b5f9 100644 --- a/lib/plausible_web/components/site/feature.ex +++ b/lib/plausible_web/components/site/feature.ex @@ -26,7 +26,7 @@ defmodule PlausibleWeb.Components.Site.Feature do class={@class} > <.toggle_submit set_to={@current_setting} disabled?={@disabled?}> - Show {String.downcase(@feature_mod.display_name())} in the dashboard + Show in dashboard diff --git a/lib/plausible_web/controllers/site_controller.ex b/lib/plausible_web/controllers/site_controller.ex index 8f9e1f67f2be..f0e16a687fbf 100644 --- a/lib/plausible_web/controllers/site_controller.ex +++ b/lib/plausible_web/controllers/site_controller.ex @@ -163,9 +163,19 @@ defmodule PlausibleWeb.SiteController do def settings_visibility(conn, _params) do site = conn.assigns[:site] + has_shared_links? = + Repo.exists?( + from(l in Plausible.Site.SharedLink, + where: + l.site_id == ^site.id and + l.name not in ^Plausible.Sites.shared_link_special_names() + ) + ) + conn |> render("settings_visibility.html", site: site, + has_shared_links?: has_shared_links?, dogfood_page_path: "/:dashboard/settings/visibility", connect_live_socket: true, layout: {PlausibleWeb.LayoutView, "site_settings.html"} @@ -173,8 +183,19 @@ defmodule PlausibleWeb.SiteController do end def settings_goals(conn, _params) do + site = conn.assigns[:site] + + has_goals? = + Repo.exists?( + from(g in Plausible.Goal, + where: g.site_id == ^site.id + ) + ) + conn |> render("settings_goals.html", + site: site, + has_goals?: has_goals?, dogfood_page_path: "/:dashboard/settings/goals", connect_live_socket: true, layout: {PlausibleWeb.LayoutView, "site_settings.html"} @@ -182,8 +203,19 @@ defmodule PlausibleWeb.SiteController do end def settings_funnels(conn, _params) do + site = conn.assigns[:site] + + has_funnels? = + Repo.exists?( + from(f in Plausible.Funnel, + where: f.site_id == ^site.id + ) + ) + conn |> render("settings_funnels.html", + site: site, + has_funnels?: has_funnels?, dogfood_page_path: "/:dashboard/settings/funnels", connect_live_socket: true, layout: {PlausibleWeb.LayoutView, "site_settings.html"} @@ -191,8 +223,15 @@ defmodule PlausibleWeb.SiteController do end def settings_props(conn, _params) do + site = conn.assigns[:site] + + has_props? = + site.allowed_event_props && length(site.allowed_event_props) > 0 + conn |> render("settings_props.html", + site: site, + has_props?: has_props?, dogfood_page_path: "/:dashboard/settings/properties", layout: {PlausibleWeb.LayoutView, "site_settings.html"}, connect_live_socket: true @@ -267,9 +306,17 @@ defmodule PlausibleWeb.SiteController do def settings_imports_exports(conn, _params) do site = conn.assigns.site + has_imports? = + Repo.exists?( + from(i in Plausible.Imported.SiteImport, + where: i.site_id == ^site.id + ) + ) + conn |> render("settings_imports_exports.html", site: site, + has_imports?: has_imports?, dogfood_page_path: "/:dashboard/settings/imports-exports", connect_live_socket: true, layout: {PlausibleWeb.LayoutView, "site_settings.html"} diff --git a/lib/plausible_web/live/goal_settings/list.ex b/lib/plausible_web/live/goal_settings/list.ex index 1153c959944d..cc2b94bf9599 100644 --- a/lib/plausible_web/live/goal_settings/list.ex +++ b/lib/plausible_web/live/goal_settings/list.ex @@ -16,17 +16,19 @@ defmodule PlausibleWeb.Live.GoalSettings.List do ~H"""
- <.filter_bar filter_text={@filter_text} placeholder="Search Goals"> - <.button - id="add-goal-button" - phx-click="add-goal" - mt?={false} - x-data - x-on:click={Modal.JS.preopen("goals-form-modal")} - > - Add goal - - + <%= if String.trim(@filter_text) != "" || Enum.count(@goals) > 0 do %> + <.filter_bar filter_text={@filter_text} placeholder="Search Goals"> + <.button + id="add-goal-button" + phx-click="add-goal" + mt?={false} + x-data + x-on:click={Modal.JS.preopen("goals-form-modal")} + > + Add goal + + + <% end %> <%= if Enum.count(@goals) > 0 do %> <.table rows={@goals}> @@ -89,17 +91,32 @@ defmodule PlausibleWeb.Live.GoalSettings.List do <% else %> -

- + <%= if String.trim(@filter_text) != "" do %> +

No goals found for this site. Please refine or <.styled_link phx-click="reset-filter-text" id="reset-filter-hint"> reset your search. - - - No goals configured for this site. - -

+

+ <% else %> +
+

+ Create your first goal +

+

+ Define actions that you want your users to take, like visiting a certain page, submitting a form, etc. <.styled_link href="https://plausible.io/docs/goal-conversions" target="_blank">Learn more +

+ <.button + id="add-goal-button" + phx-click="add-goal" + x-data + x-on:click={Modal.JS.preopen("goals-form-modal")} + class="mt-4" + > + Add goal + +
+ <% end %> <% end %>
""" diff --git a/lib/plausible_web/live/imports_exports_settings.ex b/lib/plausible_web/live/imports_exports_settings.ex index 1559cd9f133e..ad694f4189b3 100644 --- a/lib/plausible_web/live/imports_exports_settings.ex +++ b/lib/plausible_web/live/imports_exports_settings.ex @@ -74,35 +74,63 @@ defmodule PlausibleWeb.Live.ImportsExportsSettings do {@import_warning} -
- <.button_link - theme="secondary" - href={Plausible.Google.API.import_authorize_url(@site.id)} - disabled={@import_in_progress? or @at_maximum?} - mt?={false} - > - Import from - Google Analytics import - - <.button_link - disabled={@import_in_progress? or @at_maximum?} - href={"/#{URI.encode_www_form(@site.domain)}/settings/import"} - mt?={false} - > - Import from CSV - -
- -

- There are no imports yet for this site. -

- -
- <.table :if={not Enum.empty?(@site_imports)} rows={@site_imports}> + <%= if Enum.empty?(@site_imports) do %> +
+

+ Import your first data +

+

+ Import data from external sources. Up to {Plausible.Imported.max_complete_imports()} imports are allowed at a time. +

+
+ <.button_link + theme="secondary" + href={Plausible.Google.API.import_authorize_url(@site.id)} + disabled={@import_in_progress? or @at_maximum?} + mt?={false} + > + Import from + Google Analytics import + + <.button_link + disabled={@import_in_progress? or @at_maximum?} + href={"/#{URI.encode_www_form(@site.domain)}/settings/import"} + mt?={false} + > + Import from CSV + +
+
+ <% else %> +
+ <.button_link + theme="secondary" + href={Plausible.Google.API.import_authorize_url(@site.id)} + disabled={@import_in_progress? or @at_maximum?} + mt?={false} + > + Import from + Google Analytics import + + <.button_link + disabled={@import_in_progress? or @at_maximum?} + href={"/#{URI.encode_www_form(@site.domain)}/settings/import"} + mt?={false} + > + Import from CSV + +
+ +
+ <.table rows={@site_imports}> <:thead> <.th>Import <.th hide_on_mobile>Date Range @@ -164,7 +192,8 @@ defmodule PlausibleWeb.Live.ImportsExportsSettings do -
+
+ <% end %> """ end diff --git a/lib/plausible_web/live/plugins/api/settings.ex b/lib/plausible_web/live/plugins/api/settings.ex index 04659818fe3d..5f8af6a3cc97 100644 --- a/lib/plausible_web/live/plugins/api/settings.ex +++ b/lib/plausible_web/live/plugins/api/settings.ex @@ -50,14 +50,29 @@ defmodule PlausibleWeb.Live.Plugins.API.Settings do )} <% end %> -
+ <%= if Enum.empty?(@displayed_tokens) do %> +
+

+ Create your first plugin token +

+

+ Control plugin access by creating tokens for third-party integrations. +

+ <.button + phx-click="create-token" + class="mt-4" + > + New plugin token + +
+ <% else %> <.filter_bar filtering_enabled?={false}> <.button phx-click="create-token" mt?={false}> Create plugin token - <.table :if={not Enum.empty?(@displayed_tokens)} rows={@displayed_tokens}> + <.table rows={@displayed_tokens}> <:thead> <.th>Description <.th hide_on_mobile>Hint @@ -86,7 +101,7 @@ defmodule PlausibleWeb.Live.Plugins.API.Settings do -
+ <% end %>
""" end diff --git a/lib/plausible_web/live/props_settings/list.ex b/lib/plausible_web/live/props_settings/list.ex index d146716fc12d..d9ca4746c193 100644 --- a/lib/plausible_web/live/props_settings/list.ex +++ b/lib/plausible_web/live/props_settings/list.ex @@ -11,11 +11,14 @@ defmodule PlausibleWeb.Live.PropsSettings.List do def render(assigns) do ~H"""
- <.filter_bar filter_text={@filter_text} placeholder="Search Properties"> - <.button phx-click="add-prop" mt?={false}> - Add property - - + <%= if String.trim(@filter_text) != "" || (is_list(@props) && length(@props) > 0) do %> + <.filter_bar filter_text={@filter_text} placeholder="Search Properties"> + <.button phx-click="add-prop" mt?={false}> + Add property + + + <% end %> + <%= if is_list(@props) && length(@props) > 0 do %> <.table id="allowed-props" rows={Enum.with_index(@props)}> <:tbody :let={{prop, index}}> @@ -32,17 +35,30 @@ defmodule PlausibleWeb.Live.PropsSettings.List do <% else %> -

- + <%= if String.trim(@filter_text) != "" do %> +

No properties found for this site. Please refine or <.styled_link phx-click="reset-filter-text" id="reset-filter-hint"> reset your search. - - - No properties configured for this site. - -

+

+ <% else %> +
+

+ Create a custom property +

+

+ Attach custom properties when sending a pageview or an event to create custom metrics. <.styled_link href="https://plausible.io/docs/custom-props/introduction" target="_blank">Learn more +

+ <.button + id="add-property-button" + phx-click="add-prop" + class="mt-4" + > + Add property + +
+ <% end %> <% end %>
""" diff --git a/lib/plausible_web/live/shared_link_settings.ex b/lib/plausible_web/live/shared_link_settings.ex index 3ebf4ea5c335..2a684e1e06b2 100644 --- a/lib/plausible_web/live/shared_link_settings.ex +++ b/lib/plausible_web/live/shared_link_settings.ex @@ -62,56 +62,72 @@ defmodule PlausibleWeb.Live.SharedLinkSettings do /> - <.filter_bar filtering_enabled?={false}> - <.button - id="add-shared-link-button" - phx-click="add-shared-link" - mt?={false} - x-data - x-on:click={Modal.JS.preopen("shared-links-form-modal")} - > - Add shared link - - - -

- No shared links configured for this site. -

- - <.table rows={@shared_links} id="shared-links-table"> - <:thead> - <.th hide_on_mobile>Name - <.th>Link - <.th invisible>Actions - - <:tbody :let={link}> - <.td truncate hide_on_mobile> - {link.name} - - - - <.td> - <.input_with_clipboard - name={link.slug} - id={link.slug} - value={Plausible.Sites.shared_link_url(@site, link)} - /> - - <.td actions> - <.edit_button - class="mt-1" - phx-click="edit-shared-link" - phx-value-slug={link.slug} - /> - <.delete_button - class="mt-1" - phx-click="delete-shared-link" - phx-value-slug={link.slug} - data-confirm="Are you sure you want to delete this shared link? The stats will not be accessible with this link anymore." - /> - - - + <%= if Enum.empty?(@shared_links) do %> +
+

+ Create your first shared link +

+

+ Share your stats privately with anyone. Links are unique, secure, and can be password-protected. <.styled_link href="https://plausible.io/docs/shared-links" target="_blank">Learn more +

+ <.button + id="add-shared-link-button" + phx-click="add-shared-link" + x-data + x-on:click={Modal.JS.preopen("shared-links-form-modal")} + class="mt-4" + > + Add shared link + +
+ <% else %> + <.filter_bar filtering_enabled?={false}> + <.button + id="add-shared-link-button" + phx-click="add-shared-link" + mt?={false} + x-data + x-on:click={Modal.JS.preopen("shared-links-form-modal")} + > + Add shared link + + + + <.table rows={@shared_links} id="shared-links-table"> + <:thead> + <.th hide_on_mobile>Name + <.th>Link + <.th invisible>Actions + + <:tbody :let={link}> + <.td truncate hide_on_mobile> + {link.name} + + + + <.td> + <.input_with_clipboard + name={link.slug} + id={link.slug} + value={Plausible.Sites.shared_link_url(@site, link)} + /> + + <.td actions> + <.edit_button + class="mt-1" + phx-click="edit-shared-link" + phx-value-slug={link.slug} + /> + <.delete_button + class="mt-1" + phx-click="delete-shared-link" + phx-value-slug={link.slug} + data-confirm="Are you sure you want to delete this shared link? The stats will not be accessible with this link anymore." + /> + + + + <% end %> """ end diff --git a/lib/plausible_web/live/shields/country_rules.ex b/lib/plausible_web/live/shields/country_rules.ex index 4fcb753b74bb..22e8a2e03bb6 100644 --- a/lib/plausible_web/live/shields/country_rules.ex +++ b/lib/plausible_web/live/shields/country_rules.ex @@ -29,76 +29,97 @@ defmodule PlausibleWeb.Live.Shields.CountryRules do ~H"""
<.settings_tiles> - <.tile docs="excluding"> + <.tile docs="excluding#exclude-visits-by-country"> <:title>Country block list - <:subtitle>Reject incoming traffic from specific countries. - <.filter_bar - :if={@country_rules_count < Shields.maximum_country_rules()} - filtering_enabled?={false} - > - <.button - id="add-country-rule" - x-data - x-on:click={Modal.JS.open("country-rule-form-modal")} - mt?={false} + <:subtitle :if={not Enum.empty?(@country_rules)}> + Reject incoming traffic from specific countries. + + + <%= if Enum.empty?(@country_rules) do %> +
+

+ Block a country +

+

+ Reject incoming traffic from specific countries. <.styled_link href="https://plausible.io/docs/excluding#exclude-visits-by-country" target="_blank">Learn more +

+ <.button + :if={@country_rules_count < Shields.maximum_country_rules()} + id="add-country-rule" + x-data + x-on:click={Modal.JS.open("country-rule-form-modal")} + class="mt-4" + > + Add country + +
+ <% else %> + <.filter_bar + :if={@country_rules_count < Shields.maximum_country_rules()} + filtering_enabled?={false} > - Add country - - - - <.notice - :if={@country_rules_count >= Shields.maximum_country_rules()} - class="mt-4" - title="Maximum number of countries reached" - theme={:gray} - > -

- You've reached the maximum number of countries you can block ({Shields.maximum_country_rules()}). Please remove one before adding another. -

- - -

- No country rules configured for this site. -

- - <.table :if={not Enum.empty?(@country_rules)} rows={@country_rules}> - <:thead> - <.th>Country - <.th hide_on_mobile>Status - <.th invisible>Actions - - <:tbody :let={rule}> - <% country = Location.Country.get_country(rule.country_code) %> - <.td> -
- - {country.flag} {country.name} - -
- - <.td hide_on_mobile> - - Blocked - - - Allowed - - - <.td actions> - <.delete_button - id={"remove-country-rule-#{rule.id}"} - phx-target={@myself} - phx-click="remove-country-rule" - phx-value-rule-id={rule.id} - data-confirm="Are you sure you want to revoke this rule?" - /> - - - + <.button + id="add-country-rule" + x-data + x-on:click={Modal.JS.open("country-rule-form-modal")} + mt?={false} + > + Add country + + + + <.notice + :if={@country_rules_count >= Shields.maximum_country_rules()} + class="mt-4" + title="Maximum number of countries reached" + theme={:gray} + > +

+ You've reached the maximum number of countries you can block ({Shields.maximum_country_rules()}). Please remove one before adding another. +

+ + +
+ <.table rows={@country_rules}> + <:thead> + <.th>Country + <.th hide_on_mobile>Status + <.th invisible>Actions + + <:tbody :let={rule}> + <% country = Location.Country.get_country(rule.country_code) %> + <.td> +
+ + {country.flag} {country.name} + +
+ + <.td hide_on_mobile> + + Blocked + + + Allowed + + + <.td actions> + <.delete_button + id={"remove-country-rule-#{rule.id}"} + phx-target={@myself} + phx-click="remove-country-rule" + phx-value-rule-id={rule.id} + data-confirm="Are you sure you want to revoke this rule?" + /> + + + +
+ <% end %> <.live_component :let={modal_unique_id} module={Modal} id="country-rule-form-modal"> <.form diff --git a/lib/plausible_web/live/shields/hostname_rules.ex b/lib/plausible_web/live/shields/hostname_rules.ex index dbb4565bdf84..503fffe0ae15 100644 --- a/lib/plausible_web/live/shields/hostname_rules.ex +++ b/lib/plausible_web/live/shields/hostname_rules.ex @@ -34,85 +34,103 @@ defmodule PlausibleWeb.Live.Shields.HostnameRules do <.settings_tiles> <.tile docs="excluding#exclude-visits-by-hostname"> <:title>Hostnames allow list - <:subtitle>Accept incoming traffic only from familiar hostnames. - <.filter_bar - :if={@hostname_rules_count < Shields.maximum_hostname_rules()} - filtering_enabled?={false} - > - <.button - id="add-hostname-rule" - x-data - x-on:click={Modal.JS.open("hostname-rule-form-modal")} - mt?={false} - > - Add hostname - - + <:subtitle :if={not Enum.empty?(@hostname_rules)}> + Accept incoming traffic only from familiar hostnames. + - <.notice - :if={@hostname_rules_count >= Shields.maximum_hostname_rules()} - class="mt-4" - title="Maximum number of hostnames reached" - theme={:gray} - > -

- You've reached the maximum number of hostnames you can block ({Shields.maximum_hostname_rules()}). Please remove one before adding another. -

- + <%= if Enum.empty?(@hostname_rules) do %> +
+

+ Allow a hostname +

+

+ Accept incoming traffic only from familiar hostnames. Traffic from all hostnames is recorded until you add your first rule. <.styled_link href="https://plausible.io/docs/excluding#exclude-visits-by-hostname" target="_blank">Learn more +

+ <.button + :if={@hostname_rules_count < Shields.maximum_hostname_rules()} + id="add-hostname-rule" + x-data + x-on:click={Modal.JS.open("hostname-rule-form-modal")} + class="mt-4" + > + Add hostname + +
+ <% else %> + <.filter_bar + :if={@hostname_rules_count < Shields.maximum_hostname_rules()} + filtering_enabled?={false} + > + <.button + id="add-hostname-rule" + x-data + x-on:click={Modal.JS.open("hostname-rule-form-modal")} + mt?={false} + > + Add hostname + + -

- No hostname rules configured for this site. - - Traffic from all hostnames is currently accepted. - -

+ <.notice + :if={@hostname_rules_count >= Shields.maximum_hostname_rules()} + class="mt-4" + title="Maximum number of hostnames reached" + theme={:gray} + > +

+ You've reached the maximum number of hostnames you can block ({Shields.maximum_hostname_rules()}). Please remove one before adding another. +

+ - <.table :if={not Enum.empty?(@hostname_rules)} rows={@hostname_rules}> - <:thead> - <.th>Hostname - <.th hide_on_mobile>Status - <.th invisible>Actions - - <:tbody :let={rule}> - <.td> -
- - {rule.hostname} - -
- - <.td hide_on_mobile> -
- - Blocked - - - Allowed - - - - -
- - <.td actions> - <.delete_button - id={"remove-hostname-rule-#{rule.id}"} - phx-target={@myself} - phx-click="remove-hostname-rule" - phx-value-rule-id={rule.id} - data-confirm="Are you sure you want to revoke this rule?" - /> - - - +
+ <.table rows={@hostname_rules}> + <:thead> + <.th>Hostname + <.th hide_on_mobile>Status + <.th invisible>Actions + + <:tbody :let={rule}> + <.td> +
+ + {rule.hostname} + +
+ + <.td hide_on_mobile> +
+ + Blocked + + + Allowed + + + + +
+ + <.td actions> + <.delete_button + id={"remove-hostname-rule-#{rule.id}"} + phx-target={@myself} + phx-click="remove-hostname-rule" + phx-value-rule-id={rule.id} + data-confirm="Are you sure you want to revoke this rule?" + /> + + + +
+ <% end %> <.live_component :let={modal_unique_id} module={Modal} id="hostname-rule-form-modal"> <.form diff --git a/lib/plausible_web/live/shields/ip_rules.ex b/lib/plausible_web/live/shields/ip_rules.ex index 850562d97661..85f150da0da3 100644 --- a/lib/plausible_web/live/shields/ip_rules.ex +++ b/lib/plausible_web/live/shields/ip_rules.ex @@ -32,88 +32,109 @@ defmodule PlausibleWeb.Live.Shields.IPRules do <.settings_tiles> <.tile docs="excluding"> <:title>IP block list - <:subtitle>Reject incoming traffic from specific IP addresses. - <.filter_bar :if={@ip_rules_count < Shields.maximum_ip_rules()} filtering_enabled?={false}> - <.button - id="add-ip-rule" - x-data - x-on:click={Modal.JS.open("ip-rule-form-modal")} - mt?={false} + <:subtitle :if={not Enum.empty?(@ip_rules)}> + Reject incoming traffic from specific IP addresses. + + + <%= if Enum.empty?(@ip_rules) do %> +
+

+ Block an IP address +

+

+ Reject incoming traffic from specific IP addresses. <.styled_link href="https://plausible.io/docs/excluding" target="_blank">Learn more +

+ <.button + :if={@ip_rules_count < Shields.maximum_ip_rules()} + id="add-ip-rule" + x-data + x-on:click={Modal.JS.open("ip-rule-form-modal")} + class="mt-4" + > + Add IP address + +
+ <% else %> + <.filter_bar :if={@ip_rules_count < Shields.maximum_ip_rules()} filtering_enabled?={false}> + <.button + id="add-ip-rule" + x-data + x-on:click={Modal.JS.open("ip-rule-form-modal")} + mt?={false} + > + Add IP address + + + + <.notice + :if={@ip_rules_count >= Shields.maximum_ip_rules()} + class="mt-4" + title="Maximum number of addresses reached" + theme={:gray} > - Add IP address - - - - <.notice - :if={@ip_rules_count >= Shields.maximum_ip_rules()} - class="mt-4" - title="Maximum number of addresses reached" - theme={:gray} - > -

- You've reached the maximum number of IP addresses you can block ({Shields.maximum_ip_rules()}). Please remove one before adding another. -

- - -

- No IP rules configured for this site. -

- - <.table :if={not Enum.empty?(@ip_rules)} rows={@ip_rules}> - <:thead> - <.th>IP address - <.th hide_on_mobile>Status - <.th hide_on_mobile>Description - <.th invisible>Actions - - <:tbody :let={rule}> - <.td max_width="max-w-40"> -
- - - YOU - - - {rule.inet} - -
- - <.td hide_on_mobile> - - Blocked - - - Allowed - - - <.td hide_on_mobile truncate> - - {rule.description} - - - -- - - - <.td actions> - <.delete_button - id={"remove-ip-rule-#{rule.id}"} - phx-target={@myself} - phx-click="remove-ip-rule" - phx-value-rule-id={rule.id} - data-confirm="Are you sure you want to revoke this rule?" - /> - - - +

+ You've reached the maximum number of IP addresses you can block ({Shields.maximum_ip_rules()}). Please remove one before adding another. +

+ + +
+ <.table rows={@ip_rules}> + <:thead> + <.th>IP address + <.th hide_on_mobile>Status + <.th hide_on_mobile>Description + <.th invisible>Actions + + <:tbody :let={rule}> + <.td max_width="max-w-40"> +
+ + + YOU + + + {rule.inet} + +
+ + <.td hide_on_mobile> + + Blocked + + + Allowed + + + <.td hide_on_mobile truncate> + + {rule.description} + + + -- + + + <.td actions> + <.delete_button + id={"remove-ip-rule-#{rule.id}"} + phx-target={@myself} + phx-click="remove-ip-rule" + phx-value-rule-id={rule.id} + data-confirm="Are you sure you want to revoke this rule?" + /> + + + +
+ <% end %> <.live_component module={Modal} id="ip-rule-form-modal"> <.form diff --git a/lib/plausible_web/live/shields/page_rules.ex b/lib/plausible_web/live/shields/page_rules.ex index 3047fa0c5ef0..6c8e78f781b0 100644 --- a/lib/plausible_web/live/shields/page_rules.ex +++ b/lib/plausible_web/live/shields/page_rules.ex @@ -34,80 +34,101 @@ defmodule PlausibleWeb.Live.Shields.PageRules do <.settings_tiles> <.tile docs="top-pages#block-traffic-from-specific-pages-or-sections"> <:title>Pages block list - <:subtitle>Reject incoming traffic for specific pages. - <.filter_bar - :if={@page_rules_count < Shields.maximum_page_rules()} - filtering_enabled?={false} - > - <.button - id="add-page-rule" - x-data - x-on:click={Modal.JS.open("page-rule-form-modal")} - mt?={false} - > - Add page - - + <:subtitle :if={not Enum.empty?(@page_rules)}> + Reject incoming traffic for specific pages. + - <.notice - :if={@page_rules_count >= Shields.maximum_page_rules()} - class="mt-4" - title="Maximum number of pages reached" - theme={:gray} - > -

- You've reached the maximum number of pages you can block ({Shields.maximum_page_rules()}). Please remove one before adding another. -

- + <%= if Enum.empty?(@page_rules) do %> +
+

+ Block a page +

+

+ Reject incoming traffic for specific pages. <.styled_link href="https://plausible.io/docs/top-pages#block-traffic-from-specific-pages-or-sections" target="_blank">Learn more +

+ <.button + :if={@page_rules_count < Shields.maximum_page_rules()} + id="add-page-rule" + x-data + x-on:click={Modal.JS.open("page-rule-form-modal")} + class="mt-4" + > + Add page + +
+ <% else %> + <.filter_bar + :if={@page_rules_count < Shields.maximum_page_rules()} + filtering_enabled?={false} + > + <.button + id="add-page-rule" + x-data + x-on:click={Modal.JS.open("page-rule-form-modal")} + mt?={false} + > + Add page + + -

- No page rules configured for this site. -

+ <.notice + :if={@page_rules_count >= Shields.maximum_page_rules()} + class="mt-4" + title="Maximum number of pages reached" + theme={:gray} + > +

+ You've reached the maximum number of pages you can block ({Shields.maximum_page_rules()}). Please remove one before adding another. +

+ - <.table :if={not Enum.empty?(@page_rules)} rows={@page_rules}> - <:thead> - <.th>Page - <.th hide_on_mobile>Status - <.th invisible>Actions - - <:tbody :let={rule}> - <.td max_width="max-w-40" truncate> - - {rule.page_path} - - - <.td hide_on_mobile> -
- - Blocked - - - Allowed - - - - -
- - <.td actions> - <.delete_button - id={"remove-page-rule-#{rule.id}"} - phx-target={@myself} - phx-click="remove-page-rule" - phx-value-rule-id={rule.id} - data-confirm="Are you sure you want to revoke this rule?" - /> - - - +
+ <.table rows={@page_rules}> + <:thead> + <.th>Page + <.th hide_on_mobile>Status + <.th invisible>Actions + + <:tbody :let={rule}> + <.td max_width="max-w-40" truncate> + + {rule.page_path} + + + <.td hide_on_mobile> +
+ + Blocked + + + Allowed + + + + +
+ + <.td actions> + <.delete_button + id={"remove-page-rule-#{rule.id}"} + phx-target={@myself} + phx-click="remove-page-rule" + phx-value-rule-id={rule.id} + data-confirm="Are you sure you want to revoke this rule?" + /> + + + +
+ <% end %> <.live_component :let={modal_unique_id} module={Modal} id="page-rule-form-modal"> <.form diff --git a/lib/plausible_web/templates/settings/api_keys.html.heex b/lib/plausible_web/templates/settings/api_keys.html.heex index a5540ab9e6f1..0b933c5ed209 100644 --- a/lib/plausible_web/templates/settings/api_keys.html.heex +++ b/lib/plausible_web/templates/settings/api_keys.html.heex @@ -8,56 +8,64 @@ <:title> API keys - <:subtitle> + <:subtitle :if={not Enum.empty?(@api_keys)}> Create and manage access. - <.filter_bar filtering_enabled?={false}> - <.button_link mt?={false} href={Routes.settings_path(@conn, :new_api_key)}> - New API Key - - + <%= if Enum.empty?(@api_keys) do %> +
+

+ Create your first API key +

+

Access your stats through the Plausible API. <.styled_link href="https://plausible.io/docs/stats-api">Learn more

+ <.button_link href={Routes.settings_path(@conn, :new_api_key)}> + New API Key + +
+ <% else %> + <.filter_bar filtering_enabled?={false}> + <.button_link mt?={false} href={Routes.settings_path(@conn, :new_api_key)}> + New API Key + + -

- No API keys configured yet. -

+ <.table rows={@api_keys}> + <:thead> + <.th> + Name + + <.th hide_on_mobile> + Key + + <.th :if={ee?()} hide_on_mobile> + Type + + <.th invisible> + Actions + + - <.table rows={@api_keys}> - <:thead> - <.th> - Name - - <.th hide_on_mobile> - Key - - <.th :if={ee?()} hide_on_mobile> - Type - - <.th invisible> - Actions - - - - <:tbody :let={api_key}> - <.td truncate max_width="max-w-40"> - {api_key.name} - - <.td hide_on_mobile> - {api_key.key_prefix} - {String.duplicate("*", 32 - 6)} - - <.td :if={ee?()}> - Stats API - Sites API - - <.td actions> - <.delete_button - method="delete" - href={Routes.settings_path(@conn, :delete_api_key, api_key.id)} - data-confirm="Are you sure you want to revoke this key? This action cannot be reversed." - /> - - - + <:tbody :let={api_key}> + <.td truncate max_width="max-w-40"> + {api_key.name} + + <.td hide_on_mobile> + {api_key.key_prefix} + {String.duplicate("*", 32 - 6)} + + <.td :if={ee?()}> + Stats API + Sites API + + <.td actions> + <.delete_button + method="delete" + href={Routes.settings_path(@conn, :delete_api_key, api_key.id)} + data-confirm="Are you sure you want to revoke this key? This action cannot be reversed." + /> + + + + <% end %> diff --git a/lib/plausible_web/templates/site/settings_funnels.html.heex b/lib/plausible_web/templates/site/settings_funnels.html.heex index 6e9a0d13db17..ca099b67b005 100644 --- a/lib/plausible_web/templates/site/settings_funnels.html.heex +++ b/lib/plausible_web/templates/site/settings_funnels.html.heex @@ -11,8 +11,8 @@ <:title> Funnels - <:subtitle> - Compose goals into funnels + <:subtitle :if={@has_funnels?}> + Compose goals into funnels to track user flows and conversion rates. {live_render(@conn, PlausibleWeb.Live.FunnelSettings, diff --git a/lib/plausible_web/templates/site/settings_goals.html.heex b/lib/plausible_web/templates/site/settings_goals.html.heex index 309295d0367f..4ec42deeeaa8 100644 --- a/lib/plausible_web/templates/site/settings_goals.html.heex +++ b/lib/plausible_web/templates/site/settings_goals.html.heex @@ -9,7 +9,7 @@ <:title> Goals - <:subtitle> + <:subtitle :if={@has_goals?}>

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

diff --git a/lib/plausible_web/templates/site/settings_imports_exports.html.heex b/lib/plausible_web/templates/site/settings_imports_exports.html.heex index a4bd11599341..bc45affb0eba 100644 --- a/lib/plausible_web/templates/site/settings_imports_exports.html.heex +++ b/lib/plausible_web/templates/site/settings_imports_exports.html.heex @@ -3,7 +3,7 @@ <:title> Import data - <:subtitle> + <:subtitle :if={@has_imports?}> Import existing data from external sources. Pick one of the options below to start a new import.
A maximum of {Plausible.Imported.max_complete_imports()} imports at any time is allowed. diff --git a/lib/plausible_web/templates/site/settings_integrations.html.heex b/lib/plausible_web/templates/site/settings_integrations.html.heex index f987fd542a17..49e5594a131a 100644 --- a/lib/plausible_web/templates/site/settings_integrations.html.heex +++ b/lib/plausible_web/templates/site/settings_integrations.html.heex @@ -156,7 +156,7 @@ <:title> Plugin tokens - <:subtitle> + <:subtitle :if={@has_plugins_tokens?}> Control plugin access. diff --git a/lib/plausible_web/templates/site/settings_props.html.heex b/lib/plausible_web/templates/site/settings_props.html.heex index c80ab7337472..a94bcdd58cc8 100644 --- a/lib/plausible_web/templates/site/settings_props.html.heex +++ b/lib/plausible_web/templates/site/settings_props.html.heex @@ -11,7 +11,7 @@ <:title> Custom properties - <:subtitle> + <:subtitle :if={@has_props?}> Attach custom properties when sending a pageview or an event to create custom metrics. diff --git a/lib/plausible_web/templates/site/settings_visibility.html.heex b/lib/plausible_web/templates/site/settings_visibility.html.heex index 05bc17b5961a..da4bf02c8963 100644 --- a/lib/plausible_web/templates/site/settings_visibility.html.heex +++ b/lib/plausible_web/templates/site/settings_visibility.html.heex @@ -38,8 +38,8 @@ <:title> Shared links - <:subtitle> - You can share your stats privately by generating a shared link. The links are impossible to guess and you can add password protection for extra security. + <:subtitle :if={@has_shared_links?}> + Share your stats privately with anyone. Links are unique, secure, and can be password-protected.
From 779dd928f0bc69f565b6a7ee554eafcbedc4ba2a Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Thu, 6 Nov 2025 09:49:22 +0100 Subject: [PATCH 2/8] Fix funnels and props functionality not hiding when toggled off - Add show_content? attribute to generic tile component - Ensure content is hidden when toggled off - Avoid rendering border and empty space when toggled off - Fix formatting --- .../lib/plausible_web/live/funnel_settings.ex | 9 +- .../live/funnel_settings/list.ex | 5 +- lib/plausible_web/components/generic.ex | 5 +- lib/plausible_web/live/goal_settings/list.ex | 5 +- .../live/imports_exports_settings.ex | 114 +++++++++--------- lib/plausible_web/live/props_settings/list.ex | 5 +- .../live/shared_link_settings.ex | 5 +- .../live/shields/country_rules.ex | 8 +- .../live/shields/hostname_rules.ex | 8 +- lib/plausible_web/live/shields/ip_rules.ex | 5 +- lib/plausible_web/live/shields/page_rules.ex | 8 +- .../templates/settings/api_keys.html.heex | 5 +- .../templates/site/settings_funnels.html.heex | 9 +- .../templates/site/settings_goals.html.heex | 1 + .../templates/site/settings_props.html.heex | 11 +- 15 files changed, 126 insertions(+), 77 deletions(-) diff --git a/extra/lib/plausible_web/live/funnel_settings.ex b/extra/lib/plausible_web/live/funnel_settings.ex index 93e2189de693..0ffd3fff4e55 100644 --- a/extra/lib/plausible_web/live/funnel_settings.ex +++ b/extra/lib/plausible_web/live/funnel_settings.ex @@ -70,12 +70,17 @@ defmodule PlausibleWeb.Live.FunnelSettings do />
-
+

Ready to dig into user flows?

- Set up a few goals like Signup, Visit /, or Scroll 50% on /blog/* first, then return here to build your first funnel. + Set up a few goals like Signup, Visit /, or + Scroll 50% on /blog/* + first, then return here to build your first funnel.

<.button_link class="mt-4" diff --git a/extra/lib/plausible_web/live/funnel_settings/list.ex b/extra/lib/plausible_web/live/funnel_settings/list.ex index 0e777aa3982c..5ef546cbd80e 100644 --- a/extra/lib/plausible_web/live/funnel_settings/list.ex +++ b/extra/lib/plausible_web/live/funnel_settings/list.ex @@ -57,7 +57,10 @@ defmodule PlausibleWeb.Live.FunnelSettings.List do Create your first funnel

- Compose goals into funnels to track user flows and conversion rates. <.styled_link href="https://plausible.io/docs/funnel-analysis" target="_blank">Learn more + Compose goals into funnels to track user flows and conversion rates. + <.styled_link href="https://plausible.io/docs/funnel-analysis" target="_blank"> + Learn more +

<.button id="add-funnel-button" diff --git a/lib/plausible_web/components/generic.ex b/lib/plausible_web/components/generic.ex index 466f88096529..cda27ed0692c 100644 --- a/lib/plausible_web/components/generic.ex +++ b/lib/plausible_web/components/generic.ex @@ -487,6 +487,7 @@ defmodule PlausibleWeb.Components.Generic do attr :current_team, :any, default: nil attr :site, :any attr :conn, :any + attr :show_content?, :boolean, default: true def tile(assigns) do ~H""" @@ -507,8 +508,8 @@ defmodule PlausibleWeb.Components.Generic do conn={@conn} /> -
-
+
+
<%= if @feature_mod do %>

- Define actions that you want your users to take, like visiting a certain page, submitting a form, etc. <.styled_link href="https://plausible.io/docs/goal-conversions" target="_blank">Learn more + Define actions that you want your users to take, like visiting a certain page, submitting a form, etc. + <.styled_link href="https://plausible.io/docs/goal-conversions" target="_blank"> + Learn more +

<.button id="add-goal-button" diff --git a/lib/plausible_web/live/imports_exports_settings.ex b/lib/plausible_web/live/imports_exports_settings.ex index ad694f4189b3..4facef50ece1 100644 --- a/lib/plausible_web/live/imports_exports_settings.ex +++ b/lib/plausible_web/live/imports_exports_settings.ex @@ -131,67 +131,67 @@ defmodule PlausibleWeb.Live.ImportsExportsSettings do
<.table rows={@site_imports}> - <:thead> - <.th>Import - <.th hide_on_mobile>Date Range - <.th hide_on_mobile> -
Pageviews
- - <.th invisible>Actions - + <:thead> + <.th>Import + <.th hide_on_mobile>Date Range + <.th hide_on_mobile> +
Pageviews
+ + <.th invisible>Actions + - <:tbody :let={entry}> - <.td max_width="max-w-40"> -
-
- - <.spinner - :if={entry.live_status == SiteImport.importing()} - class="block size-5 text-indigo-600 dark:text-green-600" - /> - - + <:tbody :let={entry}> + <.td max_width="max-w-40"> +
+
+ + <.spinner + :if={entry.live_status == SiteImport.importing()} + class="block size-5 text-indigo-600 dark:text-green-600" + /> + + +
+
+ {Plausible.Imported.SiteImport.label(entry.site_import)} +
-
- {Plausible.Imported.SiteImport.label(entry.site_import)} -
-
- + - <.td hide_on_mobile> - {format_date(entry.site_import.start_date)} - {format_date(entry.site_import.end_date)} - + <.td hide_on_mobile> + {format_date(entry.site_import.start_date)} - {format_date(entry.site_import.end_date)} + - <.td> -
- {if entry.live_status == SiteImport.completed(), - do: - PlausibleWeb.StatsView.large_number_format( - pageview_count(entry.site_import, @pageview_counts) - )} -
- - <.td actions> - <.delete_button - href={"/#{URI.encode_www_form(@site.domain)}/settings/forget-import/#{entry.site_import.id}"} - method="delete" - data-confirm="Are you sure you want to delete this import?" - /> - - - + <.td> +
+ {if entry.live_status == SiteImport.completed(), + do: + PlausibleWeb.StatsView.large_number_format( + pageview_count(entry.site_import, @pageview_counts) + )} +
+ + <.td actions> + <.delete_button + href={"/#{URI.encode_www_form(@site.domain)}/settings/forget-import/#{entry.site_import.id}"} + method="delete" + data-confirm="Are you sure you want to delete this import?" + /> + + +
<% end %> """ diff --git a/lib/plausible_web/live/props_settings/list.ex b/lib/plausible_web/live/props_settings/list.ex index d9ca4746c193..341dca08a1e2 100644 --- a/lib/plausible_web/live/props_settings/list.ex +++ b/lib/plausible_web/live/props_settings/list.ex @@ -48,7 +48,10 @@ defmodule PlausibleWeb.Live.PropsSettings.List do Create a custom property

- Attach custom properties when sending a pageview or an event to create custom metrics. <.styled_link href="https://plausible.io/docs/custom-props/introduction" target="_blank">Learn more + Attach custom properties when sending a pageview or an event to create custom metrics. + <.styled_link href="https://plausible.io/docs/custom-props/introduction" target="_blank"> + Learn more +

<.button id="add-property-button" diff --git a/lib/plausible_web/live/shared_link_settings.ex b/lib/plausible_web/live/shared_link_settings.ex index 2a684e1e06b2..fcbcbd78066c 100644 --- a/lib/plausible_web/live/shared_link_settings.ex +++ b/lib/plausible_web/live/shared_link_settings.ex @@ -68,7 +68,10 @@ defmodule PlausibleWeb.Live.SharedLinkSettings do Create your first shared link

- Share your stats privately with anyone. Links are unique, secure, and can be password-protected. <.styled_link href="https://plausible.io/docs/shared-links" target="_blank">Learn more + Share your stats privately with anyone. Links are unique, secure, and can be password-protected. + <.styled_link href="https://plausible.io/docs/shared-links" target="_blank"> + Learn more +

<.button id="add-shared-link-button" diff --git a/lib/plausible_web/live/shields/country_rules.ex b/lib/plausible_web/live/shields/country_rules.ex index 22e8a2e03bb6..067fafdd04de 100644 --- a/lib/plausible_web/live/shields/country_rules.ex +++ b/lib/plausible_web/live/shields/country_rules.ex @@ -41,7 +41,13 @@ defmodule PlausibleWeb.Live.Shields.CountryRules do Block a country

- Reject incoming traffic from specific countries. <.styled_link href="https://plausible.io/docs/excluding#exclude-visits-by-country" target="_blank">Learn more + Reject incoming traffic from specific countries. + <.styled_link + href="https://plausible.io/docs/excluding#exclude-visits-by-country" + target="_blank" + > + Learn more +

<.button :if={@country_rules_count < Shields.maximum_country_rules()} diff --git a/lib/plausible_web/live/shields/hostname_rules.ex b/lib/plausible_web/live/shields/hostname_rules.ex index 503fffe0ae15..3f355e69e420 100644 --- a/lib/plausible_web/live/shields/hostname_rules.ex +++ b/lib/plausible_web/live/shields/hostname_rules.ex @@ -44,7 +44,13 @@ defmodule PlausibleWeb.Live.Shields.HostnameRules do Allow a hostname

- Accept incoming traffic only from familiar hostnames. Traffic from all hostnames is recorded until you add your first rule. <.styled_link href="https://plausible.io/docs/excluding#exclude-visits-by-hostname" target="_blank">Learn more + Accept incoming traffic only from familiar hostnames. Traffic from all hostnames is recorded until you add your first rule. + <.styled_link + href="https://plausible.io/docs/excluding#exclude-visits-by-hostname" + target="_blank" + > + Learn more +

<.button :if={@hostname_rules_count < Shields.maximum_hostname_rules()} diff --git a/lib/plausible_web/live/shields/ip_rules.ex b/lib/plausible_web/live/shields/ip_rules.ex index 85f150da0da3..8e7208b7c6b3 100644 --- a/lib/plausible_web/live/shields/ip_rules.ex +++ b/lib/plausible_web/live/shields/ip_rules.ex @@ -42,7 +42,10 @@ defmodule PlausibleWeb.Live.Shields.IPRules do Block an IP address

- Reject incoming traffic from specific IP addresses. <.styled_link href="https://plausible.io/docs/excluding" target="_blank">Learn more + Reject incoming traffic from specific IP addresses. + <.styled_link href="https://plausible.io/docs/excluding" target="_blank"> + Learn more +

<.button :if={@ip_rules_count < Shields.maximum_ip_rules()} diff --git a/lib/plausible_web/live/shields/page_rules.ex b/lib/plausible_web/live/shields/page_rules.ex index 6c8e78f781b0..a76af986f679 100644 --- a/lib/plausible_web/live/shields/page_rules.ex +++ b/lib/plausible_web/live/shields/page_rules.ex @@ -44,7 +44,13 @@ defmodule PlausibleWeb.Live.Shields.PageRules do Block a page

- Reject incoming traffic for specific pages. <.styled_link href="https://plausible.io/docs/top-pages#block-traffic-from-specific-pages-or-sections" target="_blank">Learn more + Reject incoming traffic for specific pages. + <.styled_link + href="https://plausible.io/docs/top-pages#block-traffic-from-specific-pages-or-sections" + target="_blank" + > + Learn more +

<.button :if={@page_rules_count < Shields.maximum_page_rules()} diff --git a/lib/plausible_web/templates/settings/api_keys.html.heex b/lib/plausible_web/templates/settings/api_keys.html.heex index 0b933c5ed209..c19f8de085b4 100644 --- a/lib/plausible_web/templates/settings/api_keys.html.heex +++ b/lib/plausible_web/templates/settings/api_keys.html.heex @@ -17,7 +17,10 @@

Create your first API key

-

Access your stats through the Plausible API. <.styled_link href="https://plausible.io/docs/stats-api">Learn more

+

+ Access your stats through the Plausible API. + <.styled_link href="https://plausible.io/docs/stats-api">Learn more +

<.button_link href={Routes.settings_path(@conn, :new_api_key)}> New API Key diff --git a/lib/plausible_web/templates/site/settings_funnels.html.heex b/lib/plausible_web/templates/site/settings_funnels.html.heex index ca099b67b005..4ba39574acce 100644 --- a/lib/plausible_web/templates/site/settings_funnels.html.heex +++ b/lib/plausible_web/templates/site/settings_funnels.html.heex @@ -3,6 +3,7 @@ docs="funnel-analysis" feature_mod={Plausible.Billing.Feature.Funnels} feature_toggle?={true} + show_content?={!Plausible.Billing.Feature.Funnels.opted_out?(@site)} current_role={@site_role} current_team={@site_team} site={@site} @@ -15,8 +16,10 @@ Compose goals into funnels to track user flows and conversion rates. - {live_render(@conn, PlausibleWeb.Live.FunnelSettings, - session: %{"site_id" => @site.id, "domain" => @site.domain} - )} +
+ {live_render(@conn, PlausibleWeb.Live.FunnelSettings, + session: %{"site_id" => @site.id, "domain" => @site.domain} + )} +
diff --git a/lib/plausible_web/templates/site/settings_goals.html.heex b/lib/plausible_web/templates/site/settings_goals.html.heex index 4ec42deeeaa8..376b9cd5e52e 100644 --- a/lib/plausible_web/templates/site/settings_goals.html.heex +++ b/lib/plausible_web/templates/site/settings_goals.html.heex @@ -3,6 +3,7 @@ docs="goal-conversions" feature_mod={Plausible.Billing.Feature.Goals} feature_toggle?={true} + show_content?={!Plausible.Billing.Feature.Goals.opted_out?(@site)} site={@site} conn={@conn} > diff --git a/lib/plausible_web/templates/site/settings_props.html.heex b/lib/plausible_web/templates/site/settings_props.html.heex index a94bcdd58cc8..f3331c323710 100644 --- a/lib/plausible_web/templates/site/settings_props.html.heex +++ b/lib/plausible_web/templates/site/settings_props.html.heex @@ -3,6 +3,7 @@ docs="custom-props/introduction" feature_mod={Plausible.Billing.Feature.Props} feature_toggle?={true} + show_content?={!Plausible.Billing.Feature.Props.opted_out?(@site)} site={@site} current_role={@site_role} current_team={@site_team} @@ -16,9 +17,11 @@ create custom metrics. - {live_render(@conn, PlausibleWeb.Live.PropsSettings, - id: "props-form", - session: %{"site_id" => @site.id, "domain" => @site.domain} - )} +
+ {live_render(@conn, PlausibleWeb.Live.PropsSettings, + id: "props-form", + session: %{"site_id" => @site.id, "domain" => @site.domain} + )} +
From 39d7dbd99ed4d9b4586b7013f176610d08cb5fe8 Mon Sep 17 00:00:00 2001 From: Sanne de Vries Date: Thu, 13 Nov 2025 12:37:05 +0100 Subject: [PATCH 3/8] Update personal sites empty state --- lib/plausible_web/live/sites.ex | 47 +++++++++++++++++++++----- test/plausible_web/live/sites_test.exs | 8 ++--- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/lib/plausible_web/live/sites.ex b/lib/plausible_web/live/sites.ex index 44ebd2eab160..003fb6480c63 100644 --- a/lib/plausible_web/live/sites.ex +++ b/lib/plausible_web/live/sites.ex @@ -88,7 +88,14 @@ defmodule PlausibleWeb.Live.Sites do