Skip to content

Commit ce7f530

Browse files
committed
Bug 1940476 - Add triggers for "Tab group created" and "Tab group closed" events; and targeting for counting tab groups r=dao,omc-reviewers,aminomancer,negin
Differential Revision: https://phabricator.services.mozilla.com/D233953
1 parent f202505 commit ce7f530

File tree

6 files changed

+217
-1
lines changed

6 files changed

+217
-1
lines changed

browser/components/asrouter/docs/targeting-attributes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Please note that some targeting attributes require stricter controls on the tele
2121
* [canCreateSelectableProfiles](#cancreateselectableprofiles)
2222
* [creditCardsSaved](#creditcardssaved)
2323
* [currentDate](#currentdate)
24+
* [currentTabGroups](#currentTabGroups)
2425
* [defaultPDFHandler](#defaultpdfhandler)
2526
* [devToolsOpenedCount](#devtoolsopenedcount)
2627
* [distributionId](#distributionid)
@@ -67,6 +68,7 @@ Please note that some targeting attributes require stricter controls on the tele
6768
* [providerCohorts](#providercohorts)
6869
* [recentBookmarks](#recentbookmarks)
6970
* [region](#region)
71+
* [savedTabGroups](#savedtabgroups)
7072
* [screenImpressions](#screenimpressions)
7173
* [searchEngines](#searchengines)
7274
* [sync](#sync)
@@ -620,6 +622,13 @@ Pref used by system administrators to disallow add-ons from installed altogether
620622
```ts
621623
declare const xpinstallEnabled: boolean;
622624
```
625+
### `currentTabGroups`
626+
627+
Returns the number of currently open tab groups.
628+
629+
### `savedTabGroups`
630+
631+
Returns the number of tab groups the user has saved.
623632

624633
### `hasPinnedTabs`
625634

browser/components/asrouter/modules/ASRouterTargeting.sys.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
5353
// eslint-disable-next-line mozilla/no-browser-refs-in-toolkit
5454
SelectableProfileService:
5555
"resource:///modules/profiles/SelectableProfileService.sys.mjs",
56+
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
5657
TargetingContext: "resource://messaging-system/targeting/Targeting.sys.mjs",
5758
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
5859
TelemetrySession: "resource://gre/modules/TelemetrySession.sys.mjs",
@@ -748,6 +749,18 @@ const TargetingGetters = {
748749
get needsUpdate() {
749750
return QueryCache.queries.CheckBrowserNeedsUpdate.get();
750751
},
752+
get savedTabGroups() {
753+
return lazy.SessionStore.getSavedTabGroups().length;
754+
},
755+
get currentTabGroups() {
756+
let win = lazy.BrowserWindowTracker.getTopWindow();
757+
// If there's no window, there can't be any current tab groups.
758+
if (!win) {
759+
return 0;
760+
}
761+
let totalTabGroups = win.gBrowser.getAllTabGroups().length;
762+
return totalTabGroups;
763+
},
751764
get hasPinnedTabs() {
752765
for (let win of Services.wm.getEnumerator("navigator:browser")) {
753766
if (win.closed || !win.ownerGlobal.gBrowser) {

browser/components/asrouter/modules/ASRouterTriggerListeners.sys.mjs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,104 @@ export const ASRouterTriggerListeners = new Map([
865865
},
866866
},
867867
],
868+
[
869+
"tabGroupCreated",
870+
{
871+
id: "tabGroupCreated",
872+
_initialized: false,
873+
_triggerHandler: null,
874+
// Number of tab groups the user created this session
875+
_tabGroupsCreated: 0,
876+
877+
init(triggerHandler) {
878+
this._triggerHandler = triggerHandler;
879+
if (!this._initialized) {
880+
lazy.EveryWindow.registerCallback(
881+
this.id,
882+
win => {
883+
win.addEventListener("TabGroupCreateDone", this);
884+
},
885+
win => {
886+
win.removeEventListener("TabGroupCreateDone", this);
887+
}
888+
);
889+
this._initialized = true;
890+
}
891+
},
892+
handleEvent(event) {
893+
if (this._initialized) {
894+
if (!event.target.ownerGlobal.gBrowser) {
895+
return;
896+
}
897+
const { gBrowser } = event.target.ownerGlobal;
898+
this._tabGroupsCreated++;
899+
this._triggerHandler(gBrowser.selectedBrowser, {
900+
id: this.id,
901+
context: {
902+
tabGroupsCreatedCount: this._tabGroupsCreated,
903+
},
904+
});
905+
}
906+
},
907+
uninit() {
908+
if (this._initialized) {
909+
lazy.EveryWindow.unregisterCallback(this.id);
910+
this._initialized = false;
911+
this._triggerHandler = null;
912+
this._tabGroupsCreated = 0;
913+
}
914+
},
915+
},
916+
],
917+
[
918+
"tabGroupClosed",
919+
{
920+
id: "tabGroupClosed",
921+
_initialized: false,
922+
_triggerHandler: null,
923+
// Number of tab groups the user closed this session
924+
_tabGroupsClosed: 0,
925+
926+
init(triggerHandler) {
927+
this._triggerHandler = triggerHandler;
928+
if (!this._initialized) {
929+
lazy.EveryWindow.registerCallback(
930+
this.id,
931+
win => {
932+
win.addEventListener("TabGroupRemoved", this);
933+
},
934+
win => {
935+
win.removeEventListener("TabGroupRemoved", this);
936+
}
937+
);
938+
this._initialized = true;
939+
}
940+
},
941+
handleEvent(event) {
942+
if (this._initialized) {
943+
if (!event.target.ownerGlobal.gBrowser) {
944+
return;
945+
}
946+
const { gBrowser } = event.target.ownerGlobal;
947+
this._tabGroupsClosed++;
948+
this._triggerHandler(gBrowser.selectedBrowser, {
949+
id: this.id,
950+
context: {
951+
tabGroupsClosedCount: this._tabGroupsClosed,
952+
},
953+
});
954+
}
955+
},
956+
uninit() {
957+
if (this._initialized) {
958+
lazy.EveryWindow.unregisterCallback(this.id);
959+
this._initialized = false;
960+
this._triggerHandler = null;
961+
this._tabGroupsClosed = 0;
962+
}
963+
},
964+
},
965+
],
868966
[
869967
"activityAfterIdle",
870968
{

browser/components/asrouter/modules/PanelTestProvider.sys.mjs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,61 @@ const isMSIX =
1919
Services.sysinfo.getProperty("hasWinPackageId", false);
2020

2121
const MESSAGES = () => [
22+
{
23+
id: "CLOSE_TAB_GROUP_TEST_CALLOUT",
24+
template: "feature_callout",
25+
groups: ["cfr"],
26+
content: {
27+
id: "CLOSE_TAB_GROUP_TEST_CALLOUT",
28+
template: "multistage",
29+
backdrop: "transparent",
30+
transitions: false,
31+
screens: [
32+
{
33+
id: "CLOSE_TAB_GROUP_TEST_CALLOUT",
34+
anchors: [
35+
{
36+
selector: "#alltabs-button",
37+
panel_position: {
38+
anchor_attachment: "bottomcenter",
39+
callout_attachment: "topright",
40+
},
41+
},
42+
],
43+
content: {
44+
position: "callout",
45+
padding: 16,
46+
width: "412px",
47+
title_logo: {
48+
imageURL:
49+
"chrome://browser/content/asrouter/assets/smiling-fox-icon.svg",
50+
width: "24px",
51+
height: "24px",
52+
marginInline: "0 16px",
53+
},
54+
title: {
55+
raw: "If you close a tab group, you can reopen it here anytime.",
56+
},
57+
primary_button: {
58+
label: {
59+
raw: "Got it",
60+
},
61+
action: {
62+
dismiss: true,
63+
},
64+
},
65+
},
66+
},
67+
],
68+
},
69+
targeting: "tabGroupsClosedCount == 1",
70+
trigger: {
71+
id: "tabGroupClosed",
72+
},
73+
frequency: {
74+
lifetime: 1,
75+
},
76+
},
2277
{
2378
id: "CONTENT_TILES_TEST",
2479
targeting: 'providerCohorts.panel_local_testing == "SHOW_TEST"',

browser/components/asrouter/tests/xpcshell/test_PanelTestProvider.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ add_task(async function test_PanelTestProvider() {
2323
milestone_message: 0,
2424
update_action: 1,
2525
spotlight: 6,
26-
feature_callout: 4,
26+
feature_callout: 5,
2727
pb_newtab: 2,
2828
toast_notification: 3,
2929
bookmarks_bar_button: 1,

toolkit/components/messaging-system/schemas/TriggerActionSchemas/index.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ let patterns: string[];
5252
- [`newtabFeatureCalloutCheck`](#newtabfeaturecalloutcheck)
5353
- [`nthTabClosed`](#nthtabclosed)
5454
- [`nthTabOpened`](#nthtabopened)
55+
- [`tabGroupCreated`](#tabgroupcreated)
56+
- [`tabGroupClosed`](#tabgroupclosed)
5557
- [`activityAfterIdle`](#activityafteridle)
5658
- [`cookieBannerDetected`](#cookiebannerdetected)
5759
- [`cookieBannerHandled`](#cookiebannerhandled)
@@ -254,6 +256,45 @@ Happens when the user opens n or more tabs in a session
254256
}
255257
```
256258

259+
### `tabGroupCreated`
260+
261+
Happens whenever a user creates a tab group.
262+
263+
```js
264+
{
265+
trigger: { id: "tabGroupCreated" }
266+
}
267+
```
268+
```js
269+
// The trigger can also track the number or tab groups created in a
270+
// session, by including the tabGroupsCreatedCount context variable in targeting.
271+
// Here, the message triggers once two or more tab groups have been created,
272+
// even if the tabs were closed in between.
273+
{
274+
trigger: { id: "tabGroupCreated" },
275+
targeting: { "tabGroupsCreatedCount >= 2" }
276+
}
277+
```
278+
279+
### `tabGroupClosed`
280+
281+
Happens whenever a user uses the "Save and Close" action on a tab group.
282+
283+
```js
284+
{
285+
trigger: { id: "tabGroupClosed" }
286+
}
287+
```
288+
```js
289+
// The trigger can also track the number or tab groups closed in a
290+
// session, by including the tabGroupsClosedCount context variable in targeting.
291+
// Here, the message triggers once two tab groups have been saved and closed.
292+
{
293+
trigger: { id: "tabGroupClosed" },
294+
targeting: { "tabGroupsClosedCount >= 2" }
295+
}
296+
```
297+
257298
### `activityAfterIdle`
258299

259300
Happens when the user resumes activity after n milliseconds of inactivity. Keyboard/mouse interactions and audio playback count as activity. The idle timer is reset when the OS is put to sleep or wakes from sleep.

0 commit comments

Comments
 (0)