From f2a82cb6be470c46f5be1bd3a5a6a91e2dd57eae Mon Sep 17 00:00:00 2001 From: groovecoder Date: Thu, 6 Apr 2017 16:07:59 -0500 Subject: [PATCH 1/6] for #321: page count telemetry per activity --- docs/metrics.md | 11 ++++++ webextension/background.js | 72 +++++++++++++++++++++++++++++++------- webextension/manifest.json | 1 + 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/docs/metrics.md b/docs/metrics.md index 648af7f..135ed97 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -189,6 +189,17 @@ of a `testpilottest` telemetry ping for each scenario. } ``` +* The user goes idle + +```js + { + "uuid": , + "userContextId": , + "event": "page-requests-completed-per-activity", + "pageRequestCount": + } +``` + * The user chooses "Always Open in this Container" context menu option. (Note: We send two separate event names: one for assigning a site to a container, one for removing a site from a container.) ```js diff --git a/webextension/background.js b/webextension/background.js index 9631949..077ecdb 100644 --- a/webextension/background.js +++ b/webextension/background.js @@ -280,6 +280,20 @@ const messageHandler = { }); }); + browser.idle.onStateChanged.addListener((newState) => { + browser.tabs.query({}).then(tabs => { + for (let tab of tabs) { // eslint-disable-line prefer-const + if (newState === "idle" || newState === "locked") { + tabPageCounter.sendTabCountAndDelete(tab.id, "user-went-idle"); + } else if (newState === "active") { + tabPageCounter.initTabCounter(tab, "user-became-active"); + } + } + }).catch(e => { + throw e; + }); + }); + browser.webRequest.onCompleted.addListener((details) => { if (details.frameId !== 0 || details.tabId === -1) { return {}; @@ -333,30 +347,62 @@ const themeManager = { }; const tabPageCounter = { - counter: {}, + counters: {}, - initTabCounter(tab) { - if (tab.id in this.counter) { + initTabCounter(tab, why = "user-activated-tab") { + // When the user becomes active, + // we ONLY need to initialize the activity counter + if (tab.id in this.counters && why === "user-became-active") { + this.counters[tab.id].activity = { + "cookieStoreId": tab.cookieStoreId, + "pageRequests": 0 + }; return; } - this.counter[tab.id] = { + if (tab.id in this.counters) { + return; + } + this.counters[tab.id] = {}; + this.counters[tab.id].tab = { + "cookieStoreId": tab.cookieStoreId, + "pageRequests": 0 + }; + this.counters[tab.id].activity = { "cookieStoreId": tab.cookieStoreId, "pageRequests": 0 }; }, - sendTabCountAndDelete(tabId) { - browser.runtime.sendMessage({ - method: "sendTelemetryPayload", - event: "page-requests-completed-per-tab", - userContextId: this.counter[tabId].cookieStoreId, - pageRequestCount: this.counter[tabId].pageRequests - }); - delete this.counter[tabId]; + sendTabCountAndDelete(tabId, why = "user-closed-tab") { + if (why === "user-closed-tab") { + browser.runtime.sendMessage({ + method: "sendTelemetryPayload", + event: "page-requests-completed-per-tab", + userContextId: this.counters[tabId].tab.cookieStoreId, + pageRequestCount: this.counters[tabId].tab.pageRequests + }); + // When we send the ping because the user closed the tab, + // delete both the 'tab' and 'activity' counters + delete this.counters[tabId]; + } else if (why === "user-went-idle") { + browser.runtime.sendMessage({ + method: "sendTelemetryPayload", + event: "page-requests-completed-per-activity", + userContextId: this.counters[tabId].activity.cookieStoreId, + pageRequestCount: this.counters[tabId].activity.pageRequests + }); + // When we send the ping because the user went idle, + // only reset the 'activity' counter + this.counters[tabId].activity = { + "cookieStoreId": this.counters[tabId].tab.cookieStoreId, + "pageRequests": 0 + }; + } }, incrementTabCount(tab) { - this.counter[tab.id].pageRequests++; + this.counters[tab.id].tab.pageRequests++; + this.counters[tab.id].activity.pageRequests++; } }; diff --git a/webextension/manifest.json b/webextension/manifest.json index 4e30c9d..a5a85e0 100644 --- a/webextension/manifest.json +++ b/webextension/manifest.json @@ -24,6 +24,7 @@ "cookies", "contextMenus", "history", + "idle", "notifications", "storage", "tabs", From 856cc452fb024c755b06a1b599de925170b97bf2 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Fri, 7 Apr 2017 11:27:22 +0100 Subject: [PATCH 2/6] Fixing links that redirect creating another tab when creating an assigned tab. Fixes #421 --- webextension/background.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/webextension/background.js b/webextension/background.js index 9631949..57230b4 100644 --- a/webextension/background.js +++ b/webextension/background.js @@ -127,8 +127,21 @@ const assignManager = { this.reloadPageInContainer(options.url, siteSettings.userContextId, tab.index + 1, siteSettings.neverAsk); this.calculateContextMenu(tab); - // If the user just opened the tab, we can auto close it - if (this.CLOSEABLE_WINDOWS.has(tab.url)) { + + /* Removal of existing tabs: + We aim to open the new assigned container tab / warning prompt in it's own tab: + - As the history won't span from one container to another it seems most sane to not try and reopen a tab on history.back() + - When users open a new tab themselves we want to make sure we don't end up with three tabs as per: https://github.com/mozilla/testpilot-containers/issues/421 + If we are coming from an internal url that are used for the new tab page (CLOSEABLE_WINDOWS), we can safely close as user is unlikely losing history + Detecting redirects on "new tab" opening actions is pretty hard as we don't get tab history: + - Redirects happen from Short URLs and tracking links that act as a gateway + - Extensions don't provide a way to history crawl for tabs, we could inject content scripts to do this + however they don't run on about:blank so this would likely be just as hacky. + We capture the time the tab was created and close if it was within the timeout to try to capture pages which haven't had user interaction or history. + */ + if (this.CLOSEABLE_WINDOWS.has(tab.url) + || (messageHandler.lastCreatedTab + && messageHandler.lastCreatedTab.id === tab.id)) { browser.tabs.remove(tab.id); } return { @@ -228,6 +241,11 @@ const assignManager = { }; const messageHandler = { + // After the timer completes we assume it's a tab the user meant to keep open + // We use this to catch redirected tabs that have just opened + // If this were in platform we would change how the tab opens based on "new tab" link navigations such as ctrl+click + LAST_CREATED_TAB_TIMER: 2000, + init() { // Handles messages from index.js const port = browser.runtime.connect(); @@ -292,6 +310,15 @@ const messageHandler = { throw e; }); }, {urls: [""], types: ["main_frame"]}); + + // lets remember the last tab created so we can close it if it looks like a redirect + browser.tabs.onCreated.addListener((details) => { + this.lastCreatedTab = details; + setTimeout(() => { + this.lastCreatedTab = null; + }, this.LAST_CREATED_TAB_TIMER); + }); + } }; From 53c1b07d57f165809d8763c091472e00533dae6b Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Mon, 10 Apr 2017 14:07:49 +0100 Subject: [PATCH 3/6] Wrap assignment URLs to prevent the user not seeing the full path. Fixes #438 --- webextension/css/confirm-page.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webextension/css/confirm-page.css b/webextension/css/confirm-page.css index efbeb41..a595e4c 100644 --- a/webextension/css/confirm-page.css +++ b/webextension/css/confirm-page.css @@ -30,6 +30,10 @@ html { #redirect-url, #redirect-origin { font-weight: bold; + + /* max-inline-size is needed to force this text smaller than the layout at a mid-sized window */ + max-inline-size: 40rem; + word-break: break-all; } dfn { From 6282201b2c7794ed2c9cd6930def86e9c26cb14c Mon Sep 17 00:00:00 2001 From: groovecoder Date: Tue, 11 Apr 2017 11:36:35 -0500 Subject: [PATCH 4/6] for #321: only send activity page counts for tabs that were activated --- webextension/background.js | 50 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/webextension/background.js b/webextension/background.js index 077ecdb..cc28549 100644 --- a/webextension/background.js +++ b/webextension/background.js @@ -283,10 +283,10 @@ const messageHandler = { browser.idle.onStateChanged.addListener((newState) => { browser.tabs.query({}).then(tabs => { for (let tab of tabs) { // eslint-disable-line prefer-const - if (newState === "idle" || newState === "locked") { + if (newState === "idle") { tabPageCounter.sendTabCountAndDelete(tab.id, "user-went-idle"); - } else if (newState === "active") { - tabPageCounter.initTabCounter(tab, "user-became-active"); + } else if (newState === "active" && tab.active) { + tabPageCounter.initTabCounter(tab); } } }).catch(e => { @@ -349,32 +349,38 @@ const themeManager = { const tabPageCounter = { counters: {}, - initTabCounter(tab, why = "user-activated-tab") { - // When the user becomes active, - // we ONLY need to initialize the activity counter - if (tab.id in this.counters && why === "user-became-active") { + initTabCounter(tab) { + if (tab.id in this.counters) { + if (!("activity" in this.counters[tab.id])) { + this.counters[tab.id].activity = { + "cookieStoreId": tab.cookieStoreId, + "pageRequests": 0 + }; + } + if (!("tab" in this.counters[tab.id])) { + this.counters[tab.id].tab = { + "cookieStoreId": tab.cookieStoreId, + "pageRequests": 0 + }; + } + } else { + this.counters[tab.id] = {}; + this.counters[tab.id].tab = { + "cookieStoreId": tab.cookieStoreId, + "pageRequests": 0 + }; this.counters[tab.id].activity = { "cookieStoreId": tab.cookieStoreId, "pageRequests": 0 }; - return; } - if (tab.id in this.counters) { - return; - } - this.counters[tab.id] = {}; - this.counters[tab.id].tab = { - "cookieStoreId": tab.cookieStoreId, - "pageRequests": 0 - }; - this.counters[tab.id].activity = { - "cookieStoreId": tab.cookieStoreId, - "pageRequests": 0 - }; }, sendTabCountAndDelete(tabId, why = "user-closed-tab") { - if (why === "user-closed-tab") { + if (!(this.counters[tabId])) { + return; + } + if (why === "user-closed-tab" && this.counters[tabId].tab) { browser.runtime.sendMessage({ method: "sendTelemetryPayload", event: "page-requests-completed-per-tab", @@ -384,7 +390,7 @@ const tabPageCounter = { // When we send the ping because the user closed the tab, // delete both the 'tab' and 'activity' counters delete this.counters[tabId]; - } else if (why === "user-went-idle") { + } else if (why === "user-went-idle" && this.counters[tabId].activity) { browser.runtime.sendMessage({ method: "sendTelemetryPayload", event: "page-requests-completed-per-activity", From 9556de18bff5e6f14cf6861b8648390d4eeb5835 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Thu, 13 Apr 2017 15:22:36 +0100 Subject: [PATCH 5/6] Auto focus confirm button to make easier to use --- webextension/confirm-page.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webextension/confirm-page.html b/webextension/confirm-page.html index ca182bb..48e12f9 100644 --- a/webextension/confirm-page.html +++ b/webextension/confirm-page.html @@ -23,7 +23,7 @@
- +
From 970a7ea44199b771875457cb88e62b056a886016 Mon Sep 17 00:00:00 2001 From: groovecoder Date: Thu, 13 Apr 2017 10:17:11 -0500 Subject: [PATCH 6/6] bump version to 2.2.0 --- package.json | 2 +- webextension/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ab0f5bc..8fa61ea 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Containers Experiment", "description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.", - "version": "2.1.2", + "version": "2.2.0", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/testpilot-containers/issues" diff --git a/webextension/manifest.json b/webextension/manifest.json index a5a85e0..d8e094a 100644 --- a/webextension/manifest.json +++ b/webextension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Containers Experiment", - "version": "2.1.2", + "version": "2.2.0", "description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.", "icons": {