commit 6e53e5a0c186680163c48b9d64061cccaf3d5143
parent 0f4eb845cab77bf323f497af8cba3d2643c03a6b
Author: kpatenio <kpatenio@mozilla.com>
Date: Thu, 8 Jan 2026 23:39:43 +0000
Bug 1998827 — update site exclusions control to show the correct number of excluded sites. r=ip-protection-reviewers,fluent-reviewers,mconley,bolsson,fchasen
Differential Revision: https://phabricator.services.mozilla.com/D276134
Diffstat:
4 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
@@ -2850,7 +2850,6 @@ SettingGroupManager.registerGroups({
items: [
{
id: "ipProtectionExceptionAllListButton",
- l10nId: "ip-protection-site-exceptions-all-sites-button",
control: "moz-box-button",
},
],
diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js
@@ -1458,6 +1458,22 @@ Preferences.addSetting({
Preferences.addSetting({
id: "ipProtectionExceptionAllListButton",
deps: ["ipProtectionVisible", "ipProtectionSiteExceptionsFeatureEnabled"],
+ setup(emitChange) {
+ let permObserver = {
+ observe(subject, topic, _data) {
+ if (subject && topic === "perm-changed") {
+ let permission = subject.QueryInterface(Ci.nsIPermission);
+ if (permission.type === "ipp-vpn") {
+ emitChange();
+ }
+ }
+ },
+ };
+ Services.obs.addObserver(permObserver, "perm-changed");
+ return () => {
+ Services.obs.removeObserver(permObserver, "perm-changed");
+ };
+ },
visible: ({
ipProtectionVisible,
ipProtectionSiteExceptionsFeatureEnabled,
@@ -1478,6 +1494,24 @@ Preferences.addSetting({
params
);
},
+ getControlConfig(config) {
+ let l10nId = "ip-protection-site-exceptions-all-sites-button";
+
+ let savedExceptions = Services.perms.getAllByTypes(["ipp-vpn"]);
+ let numberOfExclusions = savedExceptions.filter(
+ perm => perm.capability === Ci.nsIPermissionManager.DENY_ACTION
+ ).length;
+
+ let l10nArgs = {
+ count: numberOfExclusions,
+ };
+
+ return {
+ ...config,
+ l10nId,
+ l10nArgs,
+ };
+ },
});
Preferences.addSetting({
id: "ipProtectionAutoStartFeatureEnabled",
diff --git a/browser/components/preferences/tests/browser_privacy_ipprotection.js b/browser/components/preferences/tests/browser_privacy_ipprotection.js
@@ -201,6 +201,101 @@ add_task(async function test_exclusions_add_button() {
);
});
+// Test that we show the correct number of site exclusions
+add_task(async function test_exclusions_count() {
+ const PERM_NAME = "ipp-vpn";
+ await setupVpnPrefs({ feature: "beta", siteExceptions: true });
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:preferences#privacy" },
+ async function (browser) {
+ let section = browser.contentDocument.getElementById(SECTION_ID);
+ let settingGroup = section.querySelector(
+ `setting-group[groupid="ipprotection"]`
+ );
+ is_element_visible(section, "#dataIPProtectionGroup is shown");
+ is_element_visible(settingGroup, "ipprotection setting group is shown");
+
+ let siteExceptionsGroup = settingGroup?.querySelector(
+ "#ipProtectionExceptions"
+ );
+ is_element_visible(siteExceptionsGroup, "Site exceptions group is shown");
+
+ let exceptionAllListButton = siteExceptionsGroup?.querySelector(
+ "#ipProtectionExceptionAllListButton"
+ );
+ is_element_visible(
+ exceptionAllListButton,
+ "Button for list of exclusions is shown"
+ );
+
+ let sitesCountUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
+ exceptionAllListButton,
+ { attributes: true, attributeFilter: ["data-l10n-args"] },
+ () => {
+ let args = exceptionAllListButton.getAttribute("data-l10n-args");
+ return args && JSON.parse(args)?.count === 0;
+ }
+ );
+
+ // Clear ipp-vpn to start with 0 exclusions
+ Services.perms.removeByType(PERM_NAME);
+
+ await sitesCountUpdatedPromise;
+
+ Assert.ok(true, "Should show 0 exclusions initially");
+
+ // Now test with 1 exclusion
+ sitesCountUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
+ exceptionAllListButton,
+ { attributes: true, attributeFilter: ["data-l10n-args"] },
+ () => {
+ let args = exceptionAllListButton.getAttribute("data-l10n-args");
+ return args && JSON.parse(args)?.count === 1;
+ }
+ );
+ let site1 = "https://example.com";
+ let principal1 =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(site1);
+ Services.perms.addFromPrincipal(
+ principal1,
+ PERM_NAME,
+ Services.perms.DENY_ACTION
+ );
+
+ await sitesCountUpdatedPromise;
+
+ Assert.ok(true, "Should show 1 exclusion after adding the first site");
+
+ // Now test with 2 exclusions
+ sitesCountUpdatedPromise = BrowserTestUtils.waitForMutationCondition(
+ exceptionAllListButton,
+ { attributes: true, attributeFilter: ["data-l10n-args"] },
+ () => {
+ let args = exceptionAllListButton.getAttribute("data-l10n-args");
+ return args && JSON.parse(args)?.count === 2;
+ }
+ );
+ let site2 = "https://example.org";
+ let principal2 =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(site2);
+ Services.perms.addFromPrincipal(
+ principal2,
+ PERM_NAME,
+ Services.perms.DENY_ACTION
+ );
+
+ await sitesCountUpdatedPromise;
+
+ Assert.ok(true, "Should show 2 exclusions after adding the second site");
+
+ // Clean up
+ Services.perms.removeByType(PERM_NAME);
+ Services.prefs.clearUserPref(ONBOARDING_MESSAGE_MASK_PREF);
+ }
+ );
+});
+
// Test that autostart checkboxes exist and map to the correct preferences
add_task(async function test_autostart_checkboxes() {
await setupVpnPrefs({
diff --git a/browser/locales-preview/ipProtection.ftl b/browser/locales-preview/ipProtection.ftl
@@ -108,9 +108,16 @@ ip-protection-learn-more = Learn more
ip-protection-site-exceptions =
.label = Site specific settings
+
+# Variables:
+# $count (number) - The number of sites saved as VPN exclusions.
ip-protection-site-exceptions-all-sites-button =
.label = Manage website settings
- .description = No websites added yet
+ .description =
+ { $count ->
+ [one] { $count } website
+ *[other] { $count } websites
+ }
ip-protection-autostart =
.label = Turn on VPN automatically