Skip to content

Commit 3d19dfc

Browse files
authored
Merge 135b3f0 into b46e1b3
2 parents b46e1b3 + 135b3f0 commit 3d19dfc

File tree

20 files changed

+410
-45
lines changed

20 files changed

+410
-45
lines changed

special-pages/pages/new-tab/app/activity/components/Activity.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useTypedTranslationWith } from '../../types.js';
77
import { useVisibility } from '../../widget-list/widget-config.provider.js';
88
import { useOnMiddleClick } from '../../utils.js';
99
import { useCustomizer } from '../../customizer/components/CustomizerMenu.js';
10-
import { useBatchedActivityApi, usePlatformName } from '../../settings.provider.js';
10+
import { useAdBlocking, useBatchedActivityApi, usePlatformName } from '../../settings.provider.js';
1111
import { CompanyIcon } from '../../components/CompanyIcon.js';
1212
import { Trans } from '../../../../../shared/components/TranslationsProvider.js';
1313
import { ActivityItem } from './ActivityItem.js';
@@ -194,6 +194,7 @@ function TrackerStatus({ id, trackersFound }) {
194194
const status = useComputed(() => activity.value.trackingStatus[id]);
195195
const other = status.value.trackerCompanies.slice(DDG_MAX_TRACKER_ICONS - 1);
196196
const companyIconsMax = other.length === 0 ? DDG_MAX_TRACKER_ICONS : DDG_MAX_TRACKER_ICONS - 1;
197+
const adBlocking = useAdBlocking();
197198

198199
const icons = status.value.trackerCompanies.slice(0, companyIconsMax).map((item, _index) => {
199200
return <CompanyIcon displayName={item.displayName} key={item} />;
@@ -210,10 +211,12 @@ function TrackerStatus({ id, trackersFound }) {
210211
}
211212

212213
if (status.value.totalCount === 0) {
213-
// prettier-ignore
214-
const text = trackersFound
215-
? t('activity_no_trackers_blocked')
216-
: t('activity_no_trackers')
214+
let text;
215+
if (trackersFound) {
216+
text = adBlocking ? t('activity_no_adsAndTrackers_blocked') : t('activity_no_trackers_blocked');
217+
} else {
218+
text = adBlocking ? t('activity_no_adsAndTrackers') : t('activity_no_trackers');
219+
}
217220
return (
218221
<p class={styles.companiesIconRow} data-testid="TrackerStatus">
219222
{text}
@@ -228,7 +231,11 @@ function TrackerStatus({ id, trackersFound }) {
228231
{otherIcon}
229232
</div>
230233
<div class={styles.companiesText}>
231-
<Trans str={t('activity_countBlockedPlural', { count: String(status.value.totalCount) })} values={{}} />
234+
{adBlocking ? (
235+
<Trans str={t('activity_countBlockedAdsAndTrackersPlural', { count: String(status.value.totalCount) })} values={{}} />
236+
) : (
237+
<Trans str={t('activity_countBlockedPlural', { count: String(status.value.totalCount) })} values={{}} />
238+
)}
232239
</div>
233240
</div>
234241
);

special-pages/pages/new-tab/app/activity/integration-tests/activity.page.js

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,24 @@ export class ActivityPage {
293293
await page.pause();
294294
}
295295

296-
async showsEmptyTrackerState() {
296+
async showsTrackersOnlyTrackerStates() {
297+
await expect(this.context().getByTestId('ActivityItem').nth(0)).toMatchAriaSnapshot(`
298+
- listitem:
299+
- link "example.com"
300+
- button "Add example.com to favorites":
301+
- img
302+
- button "Clear browsing history and data for example.com":
303+
- img
304+
- text: +1 56 tracking attempts blocked
305+
- list:
306+
- listitem:
307+
- link "/bathrooms/toilets"
308+
- text: Just now
309+
- listitem:
310+
- link "/kitchen/sinks"
311+
- text: 50 mins ago
312+
`);
313+
297314
await expect(this.context().getByTestId('ActivityItem').nth(3)).toMatchAriaSnapshot(`
298315
- listitem:
299316
- link "twitter.com"
@@ -305,32 +322,90 @@ export class ActivityPage {
305322
- list:
306323
- listitem:
307324
- link "Trending Topics"
308-
- text: 2 days ago`);
325+
- text: 2 days ago
326+
`);
309327

310328
await expect(this.context().getByTestId('ActivityItem').nth(4)).toMatchAriaSnapshot(`
311-
- listitem:
312-
- link "app.linkedin.com"
313-
- button "Add app.linkedin.com to favorites":
314-
- img
315-
- button "Clear browsing history and data for app.linkedin.com":
316-
- img
317-
- paragraph: No trackers found
318-
- list:
319-
- listitem:
320-
- link "Profile Page"
321-
- text: 2 hrs ago
329+
- listitem:
330+
- link "app.linkedin.com"
331+
- button "Add app.linkedin.com to favorites":
332+
- img
333+
- button "Clear browsing history and data for app.linkedin.com":
334+
- img
335+
- paragraph: No trackers found
336+
- list:
337+
- listitem:
338+
- link "Profile Page"
339+
- text: 2 hrs ago
340+
`);
341+
}
342+
343+
async showsAdsAndTrackersTrackerStates() {
344+
await expect(this.context().getByTestId('ActivityItem').nth(0)).toMatchAriaSnapshot(`
345+
- listitem:
346+
- link "example.com"
347+
- button "Add example.com to favorites":
348+
- img
349+
- button "Clear browsing history and data for example.com":
350+
- img
351+
- text: +1 56 ads + Tracking attempts blocked
352+
- list:
353+
- listitem:
354+
- link "/bathrooms/toilets"
355+
- text: Just now
356+
- listitem:
357+
- link "/kitchen/sinks"
358+
- text: 50 mins ago
322359
`);
360+
361+
await expect(this.context().getByTestId('ActivityItem').nth(3)).toMatchAriaSnapshot(`
362+
- listitem:
363+
- link "twitter.com"
364+
- button "Add twitter.com to favorites":
365+
- img
366+
- button "Clear browsing history and data for twitter.com":
367+
- img
368+
- paragraph: No ads + Tracking attempts blocked
369+
- list:
370+
- listitem:
371+
- link "Trending Topics"
372+
- text: 2 days ago
373+
`);
374+
375+
await expect(this.context().getByTestId('ActivityItem').nth(4)).toMatchAriaSnapshot(`
376+
- listitem:
377+
- link "app.linkedin.com"
378+
- button "Add app.linkedin.com to favorites":
379+
- img
380+
- button "Clear browsing history and data for app.linkedin.com":
381+
- img
382+
- paragraph: No ads + Tracking attempts found
383+
- list:
384+
- listitem:
385+
- link "Profile Page"
386+
- text: 2 hrs ago
387+
`);
323388
}
324389

325-
async hasEmptyTitle() {
390+
async hasEmptyTrackersOnlyTitle() {
326391
const { page } = this;
327392
await expect(page.getByTestId('ActivityHeading')).toMatchAriaSnapshot(`
328393
- img "Privacy Shield"
329394
- heading "No recent browsing activity" [level=2]
330395
- paragraph: Recently visited sites will appear here. Keep browsing to see how many trackers we block.
331396
`);
332397
}
333-
async hasPopuplatedTitle() {
398+
399+
async hasEmptyAdsAndTrackersTitle() {
400+
const { page } = this;
401+
await expect(page.getByTestId('ActivityHeading')).toMatchAriaSnapshot(`
402+
- img "Privacy Shield"
403+
- heading "No recent browsing activity" [level=2]
404+
- paragraph: Recently visited sites will appear here. Keep browsing to see how many ads and trackers we block.
405+
`);
406+
}
407+
408+
async hasPopulatedTrackersOnlyTitle() {
334409
const { page } = this;
335410
await expect(page.getByTestId('ActivityHeading')).toMatchAriaSnapshot(`
336411
- img "Privacy Shield"
@@ -340,4 +415,15 @@ export class ActivityPage {
340415
- paragraph: Past 7 days
341416
`);
342417
}
418+
419+
async hasPopulatedAdsAndTrackersTitle() {
420+
const { page } = this;
421+
await expect(page.getByTestId('ActivityHeading')).toMatchAriaSnapshot(`
422+
- img "Privacy Shield"
423+
- heading "Total of 0 ads & tracking attempts blocked" [level=2]
424+
- button "Hide recent activity" [expanded] [pressed]:
425+
- img
426+
- paragraph: Past 7 days
427+
`);
428+
}
343429
}

special-pages/pages/new-tab/app/activity/integration-tests/activity.spec.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,13 @@ test.describe('activity widget', () => {
5959
const ap = new ActivityPage(page, ntp);
6060
await ntp.reducedMotion();
6161
await ntp.openPage({ additional: { feed: 'activity', activity: 'empty' } });
62-
await ap.hasEmptyTitle();
62+
await ap.hasEmptyTrackersOnlyTitle();
6363
await ntp.openPage({ additional: { feed: 'activity', activity: 'onlyTopLevel' } });
64-
await ap.hasPopuplatedTitle();
64+
await ap.hasPopulatedTrackersOnlyTitle();
65+
await ntp.openPage({ additional: { feed: 'activity', activity: 'empty', adBlocking: 'enabled' } });
66+
await ap.hasEmptyAdsAndTrackersTitle();
67+
await ntp.openPage({ additional: { feed: 'activity', activity: 'onlyTopLevel', adBlocking: 'enabled' } });
68+
await ap.hasPopulatedAdsAndTrackersTitle();
6569
});
6670
test('favorite item', async ({ page }, workerInfo) => {
6771
const ntp = NewtabPage.create(page, workerInfo);
@@ -119,13 +123,16 @@ test.describe('activity widget', () => {
119123
await ap.didRender();
120124
await ap.listsAtMost3TrackerCompanies();
121125
});
122-
test('supported empty trackers states', async ({ page }, workerInfo) => {
126+
test('tracker states', async ({ page }, workerInfo) => {
123127
const ntp = NewtabPage.create(page, workerInfo);
124128
const ap = new ActivityPage(page, ntp);
125129
await ntp.reducedMotion();
126130
await ntp.openPage({ additional: { feed: 'activity' } });
127131
await ap.didRender();
128-
await ap.showsEmptyTrackerState();
132+
await ap.showsTrackersOnlyTrackerStates();
133+
await ntp.openPage({ additional: { feed: 'activity', adBlocking: 'enabled' } });
134+
await ap.didRender();
135+
await ap.showsAdsAndTrackersTrackerStates();
129136
});
130137
test('after rendering and navigating to a new tab, data is re-requested on return', async ({ page }, workerInfo) => {
131138
const ntp = NewtabPage.create(page, workerInfo);

special-pages/pages/new-tab/app/activity/strings.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@
1919
"title": "<b>{count}</b> tracking attempts blocked",
2020
"note": "The main headline indicating that more than 1 attempt has been blocked. Eg: '2 tracking attempts blocked'"
2121
},
22+
"activity_noRecentAdsAndTrackers_subtitle": {
23+
"title": "Recently visited sites will appear here. Keep browsing to see how many ads and trackers we block.",
24+
"note": "Shown in the place a list of browsing history entries will be displayed."
25+
},
26+
"activity_no_adsAndTrackers": {
27+
"title": "No ads + Tracking attempts found",
28+
"note": "Placeholder message indicating that no ads and trackers are detected"
29+
},
30+
"activity_no_adsAndTrackers_blocked": {
31+
"title": "No ads + Tracking attempts blocked",
32+
"note": "Placeholder message indicating that no ads and trackers are blocked"
33+
},
34+
"activity_countBlockedAdsAndTrackersPlural": {
35+
"title": "<b>{count}</b> ads + Tracking attempts blocked",
36+
"note": "The main headline indicating that more than 1 attempt has been blocked. Eg: '2 ads + Tracking attempts blocked'"
37+
},
2238
"activity_favoriteAdd": {
2339
"title": "Add {domain} to favorites",
2440
"note": "Button label, allows the user to add the specified domain to their favorites"

special-pages/pages/new-tab/app/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export async function init(root, messaging, telemetry, baseEnvironment) {
5959
.withPlatformName(baseEnvironment.injectName)
6060
.withPlatformName(init.platform?.name)
6161
.withPlatformName(baseEnvironment.urlParams.get('platform'))
62-
.withFeatureState('customizerDrawer', init.settings?.customizerDrawer);
62+
.withFeatureState('customizerDrawer', init.settings?.customizerDrawer)
63+
.withFeatureState('adBlocking', init.settings?.adBlocking);
6364

6465
if (!window.__playwright_01) {
6566
console.log('environment:', environment);

special-pages/pages/new-tab/app/mock-transport.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ export function mockTransport() {
518518

519519
/** @type {import('../types/new-tab').NewTabPageSettings} */
520520
const settings = {};
521+
521522
if (url.searchParams.get('customizerDrawer') === 'enabled') {
522523
settings.customizerDrawer = { state: 'enabled' };
523524
if (url.searchParams.get('autoOpen') === 'true') {
@@ -527,6 +528,10 @@ export function mockTransport() {
527528
initial.customizer = customizerData();
528529
}
529530

531+
if (url.searchParams.get('adBlocking') === 'enabled') {
532+
settings.adBlocking = { state: 'enabled' };
533+
}
534+
530535
// feature flags
531536
initial.settings = settings;
532537

special-pages/pages/new-tab/app/privacy-stats/components/ActivityHeading.js

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import styles from './PrivacyStats.module.css';
44
import { ShowHideButtonCircle } from '../../components/ShowHideButton.jsx';
55
import cn from 'classnames';
66
import { h } from 'preact';
7+
import { Trans } from '../../../../../shared/components/TranslationsProvider.js';
8+
import { useAdBlocking } from '../../settings.provider.js';
79

810
/**
911
* @import enStrings from "../strings.json"
@@ -20,20 +22,35 @@ import { h } from 'preact';
2022
export function ActivityHeading({ expansion, canExpand, itemCount, trackerCount, onToggle, buttonAttrs = {} }) {
2123
const { t } = useTypedTranslationWith(/** @type {Strings} */ ({}));
2224
const [formatter] = useState(() => new Intl.NumberFormat());
25+
const adBlocking = useAdBlocking();
2326

2427
const none = itemCount === 0;
2528
const someItems = itemCount > 0;
2629
const trackerCountFormatted = formatter.format(trackerCount);
27-
const allTimeString =
28-
trackerCount === 1 ? t('stats_countBlockedSingular') : t('stats_countBlockedPlural', { count: trackerCountFormatted });
30+
31+
let allTimeString;
32+
if (trackerCount === 1) {
33+
allTimeString = adBlocking ? t('stats_countBlockedAdsAndTrackersSingular') : t('stats_countBlockedSingular');
34+
} else {
35+
allTimeString = adBlocking
36+
? t('stats_countBlockedAdsAndTrackersPlural', { count: trackerCountFormatted })
37+
: t('stats_countBlockedPlural', { count: trackerCountFormatted });
38+
}
2939

3040
return (
31-
<div className={cn(styles.heading, styles.activityVariant)} data-testid={'ActivityHeading'}>
41+
<div
42+
className={cn(styles.heading, styles.activityVariant, { [styles.adsAndTrackersVariant]: adBlocking })}
43+
data-testid={'ActivityHeading'}
44+
>
3245
<span className={styles.headingIcon}>
33-
<img src="./icons/shield.svg" alt="Privacy Shield" />
46+
<img src={adBlocking ? './icons/shield-green.svg' : './icons/shield.svg'} alt="Privacy Shield" />
3447
</span>
3548
{none && <h2 className={styles.title}>{t('activity_noRecent_title')}</h2>}
36-
{someItems && <h2 className={styles.title}>{allTimeString}</h2>}
49+
{someItems && (
50+
<h2 className={styles.title}>
51+
<Trans str={allTimeString} values={{ count: trackerCountFormatted }} />
52+
</h2>
53+
)}
3754
{canExpand && (
3855
<span className={styles.widgetExpander}>
3956
<ShowHideButtonCircle
@@ -47,8 +64,16 @@ export function ActivityHeading({ expansion, canExpand, itemCount, trackerCount,
4764
/>
4865
</span>
4966
)}
50-
{itemCount === 0 && <p className={styles.subtitle}>{t('activity_noRecent_subtitle')}</p>}
51-
{itemCount > 0 && <p className={cn(styles.subtitle, styles.uppercase)}>{t('stats_feedCountBlockedPeriod')}</p>}
67+
{itemCount === 0 && (
68+
<p className={cn(styles.subtitle, { [styles.indented]: !adBlocking })}>
69+
{adBlocking ? t('activity_noRecentAdsAndTrackers_subtitle') : t('activity_noRecent_subtitle')}
70+
</p>
71+
)}
72+
{itemCount > 0 && (
73+
<p className={cn(styles.subtitle, styles.indented, { [styles.uppercase]: !adBlocking })}>
74+
{t('stats_feedCountBlockedPeriod')}
75+
</p>
76+
)}
5277
</div>
5378
);
5479
}

0 commit comments

Comments
 (0)